/// <summary> /// Completes an asynchronous operation initiated by <see cref="BeginRequest(Message,AsyncCallback,object)" /> /// or <see cref="BeginRequest(Message,TimeSpan,AsyncCallback,object)" />. /// </summary> /// <param name="result">The <see cref="IAsyncResult" /> instance returned by <b>BeginRequest()</b>.</param> /// <returns>The correlated response message.</returns> public Message EndRequest(IAsyncResult result) { try { WcfEnvelopeMsg replyMsg; replyMsg = (WcfEnvelopeMsg)ChannelHost.Router.EndQuery(result); if (!base.CanAcceptMessages) { // This is a bit of a hack to simulate aborting pending // requests when the channel is closed. throw ServiceModelHelper.CreateObjectDisposedException(this); } // Decode the reply using (BlockStream bs = new BlockStream((Block)replyMsg.Payload)) return(encoder.ReadMessage(bs, ServiceModelHelper.MaxXmlHeaderSize)); } catch (Exception e) { throw ServiceModelHelper.GetCommunicationException(e); } }
/// <summary> /// Initiates an asynchronous request/response transmission with a specific timeout. /// </summary> /// <param name="message">The request message.</param> /// <param name="timeout">The maximum time to wait for a response.</param> /// <param name="callback">The <see cref="AsyncCallback" /> delegate to be called when the operation completes (or <c>null</c>).</param> /// <param name="state">The application specific state (or <c>null</c>).</param> /// <returns>The <see cref="IAsyncResult" /> instance to be used to track the status of the operation.</returns> /// <remarks> /// <note> /// All successful calls to <see cref="BeginRequest(Message,TimeSpan,AsyncCallback,object)" /> must /// eventually be followed by a call to <see cref="EndRequest" />. /// </note> /// </remarks> public IAsyncResult BeginRequest(Message message, TimeSpan timeout, AsyncCallback callback, object state) { using (TimedLock.Lock(this)) { ThrowIfDisposedOrNotOpen(); ServiceModelHelper.ValidateTimeout(timeout); try { using (MemoryStream ms = new MemoryStream(payloadEstimator.EstimateNextBufferSize())) { WcfEnvelopeMsg requestMsg = new WcfEnvelopeMsg(); encoder.WriteMessage(message, ms); payloadEstimator.LastPayloadSize((int)ms.Length); requestMsg.Payload = new ArraySegment <byte>(ms.GetBuffer(), 0, (int)ms.Length); return(ChannelHost.Router.BeginQuery(ep, requestMsg, callback, state)); } } catch (Exception e) { throw ServiceModelHelper.GetCommunicationException(e); } } }
private bool hostStarted; // Indicates whether call to ChannelHost.Start() is current //--------------------------------------------------------------------- // Implementation /// <summary> /// Constructor. /// </summary> /// <param name="context">The <see cref="BindingContext" /> holding the information necessary to construct the channel stack.</param> /// <exception cref="InvalidOperationException">Thrown if problems were found with the binding parameters.</exception> internal LillTekChannelListener(BindingContext context) { this.maxAcceptedChannels = ServiceModelHelper.MaxAcceptedChannels; // $todo(jeff.lill): Hardcoded bkTaskInterval = ServiceModelHelper.DefaultBkTaskInterval; // This too this.context = context; this.uri = GetListenUri(context); this.ep = ServiceModelHelper.ToMsgEP(uri); this.onBkTask = new AsyncCallback(OnBkTask); this.sessionMode = false; this.hostStarted = false; // Initialize the message encoder factory from the binding context if // one was specified. Use the binary message encoding factory otherwise. if (context.BindingParameters.FindAll <MessageEncodingBindingElement>().Count > 1) { throw new InvalidOperationException("Multiple MessageEncodingBindingElements were found in the BindingParameters of the BindingContext."); } MessageEncodingBindingElement element = context.BindingParameters.Find <MessageEncodingBindingElement>(); if (element != null) { messageEncoderFactory = element.CreateMessageEncoderFactory(); } else { messageEncoderFactory = new BinaryMessageEncodingBindingElement().CreateMessageEncoderFactory(); } }
/// <summary> /// Begins an asynchronous operation to receive a channel request (using a specified timeout). /// </summary> /// <param name="channel">The channel.</param> /// <param name="timeout">The <see cref="TimeSpan" /> value specifying the maximum time to wait for a request.</param> /// <param name="callback">The <see cref="AsyncCallback" /> delegate to be called when the operation completes (or <c>null</c>).</param> /// <param name="state">Application specific state (or <c>null</c>).</param> /// <returns>The <see cref="IAsyncResult" /> instance to be used to track the status of the operation.</returns> /// <remarks> /// <note> /// All calls to <see cref="BeginReceiveRequest" /> must eventually be followed by a call to <see cref="EndReceiveRequest" />. /// </note> /// </remarks> public IAsyncResult BeginReceiveRequest(ReplyChannel channel, TimeSpan timeout, AsyncCallback callback, object state) { AsyncResult <RequestInfo, ReplyChannel> arReceive; using (TimedLock.Lock(this)) { timeout = ServiceModelHelper.ValidateTimeout(timeout); arReceive = new AsyncResult <RequestInfo, ReplyChannel>(null, callback, state); arReceive.TTD = SysTime.Now + timeout; arReceive.InternalState = channel; arReceive.Started(ServiceModelHelper.AsyncTrace); // Check to see if we already have a queued request. if (requestQueue.Count > 0) { arReceive.Result = requestQueue.Dequeue(); arReceive.Notify(); return(arReceive); } // Otherwise queue the receive operation. receiveQueue.Enqueue(arReceive); return(arReceive); } }
/// <summary> /// Invoked during the transition of a communication object into the closed state. /// </summary> /// <remarks> /// The base class implementation calls <see cref="TerminatePendingOperations" /> and /// the associated channel manager's <see cref="ILillTekChannelManager.OnChannelCloseOrAbort" /> method. /// </remarks> protected override void OnClosed() { Exception e = ServiceModelHelper.CreateObjectDisposedException(this); TerminatePendingOperations(e); Cleanup(); channelManager.OnChannelCloseOrAbort(this, e); base.OnClosed(); }
/// <summary> /// Internal event handler. /// </summary> /// <param name="timeout"></param> /// <returns></returns> protected override TChannel OnAcceptChannel(TimeSpan timeout) { IAsyncResult arAccept; timeout = ServiceModelHelper.ValidateTimeout(timeout); arAccept = BeginAcceptChannel(timeout, null, null); return(EndAcceptChannel(arAccept)); }
/// <summary> /// Internal event handler. /// </summary> /// <param name="timeout"></param> /// <returns></returns> protected override bool OnWaitForChannel(TimeSpan timeout) { IAsyncResult arWait; timeout = ServiceModelHelper.ValidateTimeout(timeout); arWait = BeginWaitForChannel(timeout, null, null); return(EndWaitForChannel(arWait)); }
/// <summary> /// Synchronously sends a message-based request and then waits for the correlated message-based response, /// using a specific timeout value. /// </summary> /// <param name="message">The request message.</param> /// <param name="timeout">The maximum <see cref="TimeSpan" /> to wait.</param> /// <returns>The correlated response.</returns> /// <remarks> /// This override will use <paramref name="timeout" /> value passed /// as the maximum time to wait for a response. /// </remarks> public Message Request(Message message, TimeSpan timeout) { IAsyncResult arRequest; ServiceModelHelper.ValidateTimeout(timeout); arRequest = BeginRequest(message, timeout, null, null); return(EndRequest(arRequest)); }
/// <summary> /// Inserts processing on a communication object after it transitions to the opening /// state due to the invocation of an asynchronous open operation. /// </summary> /// <param name="timeout">The <see cref="TimeSpan" /> that specifies how long the on open operation has to complete before timing out.</param> /// <param name="callback">The <see cref="AsyncCallback" /> delegate to be called when the operation completes (or <c>null</c>).</param> /// <param name="state">Application specific state (or <c>null</c>).</param> /// <returns>The <see cref="IAsyncResult" /> instance to be used to track the status of the operation.</returns> /// <remarks> /// The base class implementation initiates an asynchronous operation that will /// complete immediately on another thread. /// </remarks> protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state) { ServiceModelHelper.ValidateTimeout(timeout); session.ReceiveEvent += new DuplexReceiveDelegate(OnSessionReceive); session.QueryEvent += new DuplexQueryDelegate(OnSessionQuery); session.CloseEvent += new DuplexCloseDelegate(OnSessionClose); return(session.BeginConnect(ep, callback, state)); }
/// <summary> /// Inserts processing on a communication object after it transitions to the opening /// state due to the invocation of an asynchronous open operation. /// </summary> /// <param name="timeout">The <see cref="TimeSpan" /> that specifies how long the on open operation has to complete before timing out.</param> /// <param name="callback">The <see cref="AsyncCallback" /> delegate to be called when the operation completes (or <c>null</c>).</param> /// <param name="state">Application specific state (or <c>null</c>).</param> /// <returns>The <see cref="IAsyncResult" /> instance to be used to track the status of the operation.</returns> /// <remarks> /// The base class implementation initiates an asynchronous operation that will /// complete immediately on another thread. /// </remarks> protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state) { AsyncResult arOpen; ServiceModelHelper.ValidateTimeout(timeout); arOpen = new AsyncResult(null, callback, state); arOpen.Started(ServiceModelHelper.AsyncTrace); arOpen.Notify(); return(arOpen); }
/// <summary> /// Called by derived classes when a new channel is created. /// </summary> /// <param name="channel">The new channel.</param> public virtual void AddChannel(LillTekChannelBase channel) { using (TimedLock.Lock(this)) { if (channels == null) { throw ServiceModelHelper.CreateObjectDisposedException(this); } channels.Add(channel.ID, (TInternal)channel); } }
/// <summary> /// Internal event handler. /// </summary> /// <param name="timeout"></param> /// <param name="callback"></param> /// <param name="state"></param> /// <returns></returns> protected override IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback callback, object state) { AsyncResult ar; Cleanup(ServiceModelHelper.CreateObjectDisposedException(this)); timeout = ServiceModelHelper.ValidateTimeout(timeout); ar = new AsyncResult(null, callback, state); ar.Started(ServiceModelHelper.AsyncTrace); ar.Notify(); return(ar); }
/// <summary> /// Inserts processing after a communication object transitions to the closing state /// due to the invocation of an asynchronous close operation. /// </summary> /// <param name="timeout">The <see cref="TimeSpan" /> that specifies how long the on close operation has to complete before timing out.</param> /// <param name="callback">The <see cref="AsyncCallback" /> delegate called when the operation completes (or <c>null</c>).</param> /// <param name="state">Application specific state (or <c>null</c>).</param> /// <returns>The <see cref="IAsyncResult" /> to be used to track the status of the operation.</returns> /// <remarks> /// The base class implementation initiates an asynchronous operation that will /// complete immediately on another thread. /// </remarks> protected override IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback callback, object state) { AsyncResult arClose; ServiceModelHelper.ValidateTimeout(timeout); session.Close(); arClose = new AsyncResult(null, callback, state); arClose.Started(ServiceModelHelper.AsyncTrace); arClose.Notify(); return(arClose); }
private PayloadSizeEstimator payloadEstimator; // Used to estimate the buffer required to serialize // the next message sent /// <summary> /// Constructor. /// </summary> /// <param name="channelManager">The responsible channel manager.</param> /// <param name="remoteAddress">The remote <see cref="EndpointAddress" />.</param> /// <param name="via">The first transport hop <see cref="Uri" />.</param> /// <param name="encoder">The <see cref="MessageEncoder" /> for serializing messages to the wire format.</param> public OutputChannel(ChannelManagerBase channelManager, EndpointAddress remoteAddress, Uri via, MessageEncoder encoder) : base(channelManager) { ServiceModelHelper.ValidateEP(remoteAddress.Uri); ServiceModelHelper.ValidateEP(via); this.remoteAddress = remoteAddress; this.via = via; this.encoder = encoder; this.ep = ServiceModelHelper.ToMsgEP(remoteAddress.Uri); this.payloadEstimator = new PayloadSizeEstimator(ServiceModelHelper.PayloadEstimatorSampleCount); }
/// <summary> /// Extracts the listening URI from a binding context. /// </summary> /// <param name="context">The <see cref="BindingContext" />.</param> /// <returns>The <see cref="Uri" />.</returns> /// <exception cref="ArgumentNullException">Thrown if BindingContext.ListenUriBaseAddress is not specified.</exception> /// <exception cref="ArgumentException">Thrown if the URI does not have a valid LillTek URI scheme.</exception> protected Uri GetListenUri(BindingContext context) { Uri uri; Uri baseAddress; string relativeAddress; baseAddress = context.ListenUriBaseAddress; relativeAddress = context.ListenUriRelativeAddress; if (baseAddress == null) { if (context.ListenUriMode == ListenUriMode.Unique) { baseAddress = ServiceModelHelper.CreateUniqueUri(); } else { throw new ArgumentNullException("BindingContext.ListenUriBaseAddress"); } } if (string.IsNullOrWhiteSpace(relativeAddress)) { uri = baseAddress; } else { UriBuilder ub = new UriBuilder(baseAddress); if (!ub.Path.EndsWith("/")) { ub.Path += "/"; } uri = new Uri(ub.Uri, relativeAddress); } // Verify that the URI scheme is a valid LillTek scheme. switch (uri.Scheme.ToLowerInvariant()) { case "lilltek.logical": case "lilltek.abstract": return(uri); // OK default: throw new ArgumentException(string.Format("Invalid LillTek Messaging WCF Transport scheme [{0}].", uri.Scheme), "BindingContext.ListenUriBaseAddress"); } }
/// <summary> /// Decodes the WCF <see cref="Message" /> encapsulated within a LillTek <see cref="WcfEnvelopeMsg" />. /// </summary> /// <param name="msg">The LillTek message.</param> /// <returns>The WCF <see cref="Message" />.</returns> /// <exception cref="CommunicationException">Thrown if the message could not be decoded.</exception> public Message DecodeMessage(WcfEnvelopeMsg msg) { using (BlockStream bs = new BlockStream((Block)msg.Payload)) { try { return(messageEncoderFactory.Encoder.ReadMessage(bs, ServiceModelHelper.MaxXmlHeaderSize)); } catch (Exception e) { throw ServiceModelHelper.GetCommunicationException(e); } } }
/// <summary> /// Completes an asynchronous operation initiated by one of the <b>BeginSend()</b> overrides. /// </summary> /// <param name="result">The <see cref="IAsyncResult" /> instance returned by <b>BeginSend()</b>.</param> public void EndSend(IAsyncResult result) { AsyncResult arSend = (AsyncResult)result; arSend.Wait(); try { if (arSend.Exception != null) { throw ServiceModelHelper.GetCommunicationException(arSend.Exception); } } finally { arSend.Dispose(); } }
/// <summary> /// Initiates an asynchronous attempt to receive a message within the /// specified period of time, where a boolean will ultimately be returned /// indicating success or failure rather than throwning an exception if /// an error is encountered. /// </summary> /// <param name="timeout">The maximum <see cref="TimeSpan" /> to wait for the message.</param> /// <param name="callback">The <see cref="AsyncCallback" /> delegate to be called when the operation completes (or <c>null</c>).</param> /// <param name="state">Application specific state (or <c>null</c>).</param> /// <returns>The <see cref="IAsyncResult" /> instance to be used to track the status of the operation.</returns> /// <remarks> /// All successful calls to <see cref="BeginTryReceive" /> must eventually be followed by a /// call to <see cref="EndTryReceive" />. /// </remarks> public IAsyncResult BeginTryReceive(TimeSpan timeout, AsyncCallback callback, object state) { AsyncResult <Message, object> arReceive; using (TimedLock.Lock(this)) { timeout = ServiceModelHelper.ValidateTimeout(timeout); arReceive = new AsyncResult <Message, object>(null, callback, state); arReceive.TTD = SysTime.Now + timeout; arReceive.Started(ServiceModelHelper.AsyncTrace); // Non-open channels always return true (message=null) if (base.State != CommunicationState.Opened) { arReceive.Result = null; arReceive.Notify(); return(arReceive); } // Check to see if we already have a queued message. if (msgQueue.Count > 0) { arReceive.Result = msgQueue.Dequeue(); arReceive.Notify(); return(arReceive); } // Setup to return null if the remote side of the connection // has been closed. if (!session.IsConnected) { arReceive.Notify(); return(arReceive); } // Otherwise queue the receive operation. receiveQueue.Enqueue(arReceive); return(arReceive); } }
/// <summary> /// Begins an asynchronous operation to wait for a specified period of time for a message to be received /// or queued internally by the channel. /// </summary> /// <param name="timeout">The maximum <see cref="TimeSpan" /> to wait.</param> /// <param name="callback">The <see cref="AsyncCallback" /> delegate to be called when the operation completes (or <c>null</c>).</param> /// <param name="state">Application specific state (or <c>null</c>).</param> /// <returns>The <see cref="IAsyncResult" /> instance to be used to track the status of the operation.</returns> /// <remarks> /// All successful calls to <see cref="BeginWaitForMessage" /> must eventually be followed by a call to <see cref="EndWaitForMessage" />. /// </remarks> public IAsyncResult BeginWaitForMessage(TimeSpan timeout, AsyncCallback callback, object state) { AsyncResult <bool, object> arWait; using (TimedLock.Lock(this)) { timeout = ServiceModelHelper.ValidateTimeout(timeout); arWait = new AsyncResult <bool, object>(null, callback, state); arWait.TTD = SysTime.Now + timeout; arWait.Started(ServiceModelHelper.AsyncTrace); // Non-open channels always return false if (base.State != CommunicationState.Opened) { arWait.Result = false; arWait.Notify(); return(arWait); } // Check to see if we already have a queued message. if (msgQueue.Count > 0) { arWait.Result = true; arWait.Notify(); return(arWait); } // Setup to return false if the remote side of the session // has been closed. if (!session.IsConnected) { arWait.Notify(); return(arWait); } // Otherwise queue the wait operation. waitQueue.Enqueue(arWait); return(arWait); } }
private DuplexSession session; // Underlying LillTek Messaging session /// <summary> /// Constructor. /// </summary> /// <param name="channelManager">The responsible channel manager.</param> /// <param name="remoteAddress">The remote <see cref="EndpointAddress" />.</param> /// <param name="via">The first transport hop <see cref="Uri" />.</param> /// <param name="encoder">The <see cref="MessageEncoder" /> for serializing messages to the wire format.</param> public OutputSessionChannel(ChannelManagerBase channelManager, EndpointAddress remoteAddress, Uri via, MessageEncoder encoder) : base(channelManager) { ServiceModelHelper.ValidateEP(remoteAddress.Uri); ServiceModelHelper.ValidateEP(via); this.ep = ServiceModelHelper.ToMsgEP(remoteAddress.Uri); if (ep.Broadcast) { throw new ArgumentException("Sessionful channels cannot accept broadcast endpoints.", "remoteAddress"); } this.remoteAddress = remoteAddress; this.via = via; this.encoder = encoder; this.payloadEstimator = new PayloadSizeEstimator(ServiceModelHelper.PayloadEstimatorSampleCount); this.session = ChannelHost.Router.CreateDuplexSession(); }
public void ServiceModelHelper_ValidateTimeout() { TimeSpan timeout; ServiceModelHelper.ValidateTimeout(TimeSpan.Zero); ServiceModelHelper.ValidateTimeout(TimeSpan.FromMinutes(100)); try { ServiceModelHelper.ValidateTimeout(TimeSpan.FromMinutes(-100)); Assert.Fail("Expected an ArgumentException"); } catch (ArgumentException) { } timeout = ServiceModelHelper.ValidateTimeout(TimeSpan.MaxValue); Assert.IsTrue(SysTime.Now + timeout < DateTime.MaxValue); }
/// <summary> /// Completes an asynchronous message receive operation. /// </summary> /// <param name="result">The <see cref="IAsyncResult" /> returned by one of the <b>BeginReceive()</b> overrides.</param> /// <returns>The <see cref="Message" /> received or <c>null</c> if the remote side of the session has been closed.</returns> public Message EndReceive(IAsyncResult result) { AsyncResult <Message, object> arReceive = (AsyncResult <Message, object>)result; arReceive.Wait(); try { if (arReceive.Exception != null) { throw ServiceModelHelper.GetCommunicationException(arReceive.Exception); } return(arReceive.Result); } finally { arReceive.Dispose(); } }
/// <summary> /// Completes an asynchronous channel message receive operation. /// </summary> /// <param name="result">The <see cref="IAsyncResult" /> returned by <see cref="BeginReceive" />.</param> /// <returns>The <see cref="Message" /> received.</returns> public Message EndReceive(IAsyncResult result) { AsyncResult <Message, InputChannel> arReceive = (AsyncResult <Message, InputChannel>)result; Assertion.Test(arReceive.InternalState != null, "InternalState should have been set to the channel."); arReceive.Wait(); try { if (arReceive.Exception != null) { throw ServiceModelHelper.GetCommunicationException(arReceive.Exception); } return(arReceive.Result); } finally { arReceive.Dispose(); } }
/// <summary> /// Synchronously sends a message on the output channel. /// </summary> /// <param name="message">The <see cref="Message" />.</param> /// <remarks> /// <note> /// This method does not guarantee delivery of the message. /// Messages can be silently dropped for reasons including lack of buffer /// space, network congestion, unavailable remote endpoint, etc. /// </note> /// </remarks> public void Send(Message message) { try { using (MemoryStream ms = new MemoryStream(payloadEstimator.EstimateNextBufferSize())) { WcfEnvelopeMsg envelopeMsg = new WcfEnvelopeMsg(); encoder.WriteMessage(message, ms); payloadEstimator.LastPayloadSize((int)ms.Length); envelopeMsg.Payload = new ArraySegment <byte>(ms.GetBuffer(), 0, (int)ms.Length); ChannelHost.Router.SendTo(ep, envelopeMsg); } } catch (Exception e) { throw ServiceModelHelper.GetCommunicationException(e); } }
public void ServiceModelHelper_ValidateEP() { ServiceModelHelper.ValidateEP(new Uri("lilltek.logical://test")); ServiceModelHelper.ValidateEP(new Uri("lilltek.abstract://test")); try { ServiceModelHelper.ValidateEP(new Uri("lilltek.physical://test")); Assert.Fail("Expected an ArgumentException"); } catch (ArgumentException) { } try { ServiceModelHelper.ValidateEP(new Uri("http://test")); Assert.Fail("Expected an ArgumentException"); } catch (ArgumentException) { } try { ServiceModelHelper.ValidateEP(new Uri("lilltek.logical://test:80")); Assert.Fail("Expected an ArgumentException"); } catch (ArgumentException) { } try { ServiceModelHelper.ValidateEP(new Uri("lilltek.abstract://test:80")); Assert.Fail("Expected an ArgumentException"); } catch (ArgumentException) { } }
/// <summary> /// Begins an asynchronous operation to wait for a specified period of time for a message to be received /// for a channel. /// </summary> /// <param name="channel">The channel.</param> /// <param name="timeout">The maximum <see cref="TimeSpan" /> to wait.</param> /// <param name="callback">The <see cref="AsyncCallback" /> delegate to be called when the operation completes (or <c>null</c>).</param> /// <param name="state">Application specific state (or <c>null</c>).</param> /// <returns>The <see cref="IAsyncResult" /> instance to be used to track the status of the operation.</returns> /// <remarks> /// All successful calls to <see cref="BeginWaitForMessage" /> must eventually be followed by a call to <see cref="EndWaitForMessage" />. /// </remarks> public IAsyncResult BeginWaitForMessage(InputChannel channel, TimeSpan timeout, AsyncCallback callback, object state) { AsyncResult <bool, InputChannel> arWait; using (TimedLock.Lock(this)) { timeout = ServiceModelHelper.ValidateTimeout(timeout); arWait = new AsyncResult <bool, InputChannel>(null, callback, state); arWait.TTD = SysTime.Now + timeout; arWait.InternalState = channel; arWait.Started(ServiceModelHelper.AsyncTrace); // Non-open channels always return false. if (base.State != CommunicationState.Opened) { arWait.Notify(); return(arWait); } // If we already have a queued message, dequeue it and add it to the // channel's message queue, so a subsequent call Receive() on the channel // will be assured to succeed. Then notify that the operation is complete. if (msgQueue.Count > 0) { channel.Enqueue(msgQueue.Dequeue()); arWait.Result = true; arWait.Notify(); return(arWait); } // Otherwise queue the wait operation. waitQueue.Enqueue(arWait); return(arWait); } }
/// <summary> /// Begins an asynchronous operation to wait for a specified period of time for a message to be received /// or queued internally by the channel. /// </summary> /// <param name="timeout">The maximum <see cref="TimeSpan" /> to wait.</param> /// <param name="callback">The <see cref="AsyncCallback" /> delegate to be called when the operation completes (or <c>null</c>).</param> /// <param name="state">Application specific state (or <c>null</c>).</param> /// <returns>The <see cref="IAsyncResult" /> instance to be used to track the status of the operation.</returns> /// <remarks> /// All successful calls to <see cref="BeginWaitForMessage" /> must eventually be followed by a call to <see cref="EndWaitForMessage" />. /// </remarks> public IAsyncResult BeginWaitForMessage(TimeSpan timeout, AsyncCallback callback, object state) { using (TimedLock.Lock(this)) { // Non-open channels always return false. if (base.State != CommunicationState.Opened) { AsyncResult <bool, InputChannel> arWait; // Note that TInternal==InputChannel. This is used below in EndWaitForMessage() // to distinguish between IAsyncResults returned by this class and those // returned by the listener. arWait = new AsyncResult <bool, InputChannel>(null, callback, state); arWait.Result = false; arWait.Started(ServiceModelHelper.AsyncTrace); arWait.Notify(); return(arWait); } // If the channel already has a message queued, then setup to return it. if (msgQueue.Count > 0) { AsyncResult <bool, InputChannel> arWait; // Note that TInternal==InputChannel. This is used below in EndWaitForMessage() // to distinguish between IAsyncResults returned by this class and those // returned by the listener. arWait = new AsyncResult <bool, InputChannel>(null, callback, state); arWait.Result = true; arWait.Started(ServiceModelHelper.AsyncTrace); arWait.Notify(); return(arWait); } } timeout = ServiceModelHelper.ValidateTimeout(timeout); return(listener.BeginWaitForMessage(this, timeout, callback, state)); }
/// <summary> /// Internal event handler. /// </summary> /// <param name="timeout"></param> /// <param name="callback"></param> /// <param name="state"></param> /// <returns></returns> protected override IAsyncResult OnBeginWaitForChannel(TimeSpan timeout, AsyncCallback callback, object state) { AsyncResult <bool, object> arWait; arWait = new AsyncResult <bool, object>(null, callback, state); arWait.TTD = SysTime.Now + ServiceModelHelper.ValidateTimeout(timeout); arWait.Started(ServiceModelHelper.AsyncTrace); using (TimedLock.Lock(this)) { if (channelQueue.Count > 0) { arWait.Result = true; arWait.Notify(); } else { // Give the derived class a chance to accept a channel TInternal acceptChannel; acceptChannel = GetAcceptChannel(); if (acceptChannel != null) { channelQueue.Enqueue(acceptChannel); arWait.Result = true; arWait.Notify(); } else { waitQueue.Enqueue(arWait); } } } return(arWait); }
/// <summary> /// Begins an asynchronous operation to receive a channel message (using a specified timeout). /// </summary> /// <param name="channel">The channel.</param> /// <param name="timeout">The <see cref="TimeSpan" /> value specifying the maximum time to wait for a message.</param> /// <param name="callback">The <see cref="AsyncCallback" /> delegate to be called when the operation completes (or <c>null</c>).</param> /// <param name="state">Application specific state (or <c>null</c>).</param> /// <returns>The <see cref="IAsyncResult" /> instance to be used to track the status of the operation.</returns> /// <remarks> /// <note> /// All calls to <see cref="BeginReceive" /> must eventually be followed by a call to <see cref="EndReceive" />. /// </note> /// </remarks> public IAsyncResult BeginReceive(InputChannel channel, TimeSpan timeout, AsyncCallback callback, object state) { AsyncResult <Message, InputChannel> arReceive; using (TimedLock.Lock(this)) { timeout = ServiceModelHelper.ValidateTimeout(timeout); arReceive = new AsyncResult <Message, InputChannel>(null, callback, state); arReceive.TTD = SysTime.Now + timeout; arReceive.InternalState = channel; arReceive.Started(ServiceModelHelper.AsyncTrace); // Non-open channels always return null. if (base.State != CommunicationState.Opened) { arReceive.Result = null; arReceive.Notify(); return(arReceive); } // Check to see if we already have a queued message. if (msgQueue.Count > 0) { arReceive.Result = msgQueue.Dequeue(); arReceive.Notify(); return(arReceive); } // Otherwise queue the receive operation. receiveQueue.Enqueue(arReceive); return(arReceive); } }
/// <summary> /// Internal event handler. /// </summary> /// <param name="timeout"></param> protected override void OnClose(TimeSpan timeout) { Cleanup(ServiceModelHelper.CreateObjectDisposedException(this)); }