| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456 |
- //------------------------------------------------------------
- // Copyright (c) Microsoft Corporation. All rights reserved.
- //------------------------------------------------------------
- namespace System.ServiceModel.Channels
- {
- using System.Collections.Generic;
- using System.Diagnostics;
- using System.Runtime;
- using System.ServiceModel;
- using System.ServiceModel.Diagnostics;
- using System.Threading;
- abstract class RequestChannel : ChannelBase, IRequestChannel
- {
- bool manualAddressing;
- List<IRequestBase> outstandingRequests = new List<IRequestBase>();
- EndpointAddress to;
- Uri via;
- ManualResetEvent closedEvent;
- bool closed;
- protected RequestChannel(ChannelManagerBase channelFactory, EndpointAddress to, Uri via, bool manualAddressing)
- : base(channelFactory)
- {
- if (!manualAddressing)
- {
- if (to == null)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("to");
- }
- }
- this.manualAddressing = manualAddressing;
- this.to = to;
- this.via = via;
- }
- protected bool ManualAddressing
- {
- get
- {
- return this.manualAddressing;
- }
- }
- public EndpointAddress RemoteAddress
- {
- get
- {
- return this.to;
- }
- }
- public Uri Via
- {
- get
- {
- return this.via;
- }
- }
- protected void AbortPendingRequests()
- {
- IRequestBase[] requestsToAbort = CopyPendingRequests(false);
- if (requestsToAbort != null)
- {
- foreach (IRequestBase request in requestsToAbort)
- {
- request.Abort(this);
- }
- }
- }
- protected IAsyncResult BeginWaitForPendingRequests(TimeSpan timeout, AsyncCallback callback, object state)
- {
- IRequestBase[] pendingRequests = SetupWaitForPendingRequests();
- return new WaitForPendingRequestsAsyncResult(timeout, this, pendingRequests, callback, state);
- }
- protected void EndWaitForPendingRequests(IAsyncResult result)
- {
- WaitForPendingRequestsAsyncResult.End(result);
- }
- void FinishClose()
- {
- lock (outstandingRequests)
- {
- if (!closed)
- {
- closed = true;
- if (closedEvent != null)
- {
- this.closedEvent.Close();
- }
- }
- }
- }
- IRequestBase[] SetupWaitForPendingRequests()
- {
- return this.CopyPendingRequests(true);
- }
- protected void WaitForPendingRequests(TimeSpan timeout)
- {
- IRequestBase[] pendingRequests = SetupWaitForPendingRequests();
- if (pendingRequests != null)
- {
- if (!closedEvent.WaitOne(timeout, false))
- {
- foreach (IRequestBase request in pendingRequests)
- {
- request.Abort(this);
- }
- }
- }
- FinishClose();
- }
- IRequestBase[] CopyPendingRequests(bool createEventIfNecessary)
- {
- IRequestBase[] requests = null;
- lock (outstandingRequests)
- {
- if (outstandingRequests.Count > 0)
- {
- requests = new IRequestBase[outstandingRequests.Count];
- outstandingRequests.CopyTo(requests);
- outstandingRequests.Clear();
- if (createEventIfNecessary && closedEvent == null)
- {
- closedEvent = new ManualResetEvent(false);
- }
- }
- }
- return requests;
- }
- protected void FaultPendingRequests()
- {
- IRequestBase[] requestsToFault = CopyPendingRequests(false);
- if (requestsToFault != null)
- {
- foreach (IRequestBase request in requestsToFault)
- {
- request.Fault(this);
- }
- }
- }
- public override T GetProperty<T>()
- {
- if (typeof(T) == typeof(IRequestChannel))
- {
- return (T)(object)this;
- }
- T baseProperty = base.GetProperty<T>();
- if (baseProperty != null)
- {
- return baseProperty;
- }
- return default(T);
- }
- protected override void OnAbort()
- {
- AbortPendingRequests();
- }
- void ReleaseRequest(IRequestBase request)
- {
- if (request != null)
- {
- // Synchronization of OnReleaseRequest is the
- // responsibility of the concrete implementation of request.
- request.OnReleaseRequest();
- }
- lock (outstandingRequests)
- {
- // Remove supports the connection having been removed, so don't need extra Contains() check,
- // even though this may have been removed by Abort()
- outstandingRequests.Remove(request);
- if (outstandingRequests.Count == 0)
- {
- if (!closed && closedEvent != null)
- {
- closedEvent.Set();
- }
- }
- }
- }
- void TrackRequest(IRequestBase request)
- {
- lock (outstandingRequests)
- {
- ThrowIfDisposedOrNotOpen(); // make sure that we haven't already snapshot our collection
- outstandingRequests.Add(request);
- }
- }
- public IAsyncResult BeginRequest(Message message, AsyncCallback callback, object state)
- {
- return this.BeginRequest(message, this.DefaultSendTimeout, callback, state);
- }
- public IAsyncResult BeginRequest(Message message, TimeSpan timeout, AsyncCallback callback, object state)
- {
- if (message == null)
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("message");
- if (timeout < TimeSpan.Zero)
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
- new ArgumentOutOfRangeException("timeout", timeout, SR.GetString(SR.SFxTimeoutOutOfRange0)));
- ThrowIfDisposedOrNotOpen();
- AddHeadersTo(message);
- IAsyncRequest asyncRequest = CreateAsyncRequest(message, callback, state);
- TrackRequest(asyncRequest);
- bool throwing = true;
- try
- {
- asyncRequest.BeginSendRequest(message, timeout);
- throwing = false;
- }
- finally
- {
- if (throwing)
- {
- ReleaseRequest(asyncRequest);
- }
- }
- return asyncRequest;
- }
- protected abstract IRequest CreateRequest(Message message);
- protected abstract IAsyncRequest CreateAsyncRequest(Message message, AsyncCallback callback, object state);
- public Message EndRequest(IAsyncResult result)
- {
- if (result == null)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("result");
- }
- IAsyncRequest asyncRequest = result as IAsyncRequest;
- if (asyncRequest == null)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("result", SR.GetString(SR.InvalidAsyncResult));
- }
- try
- {
- Message reply = asyncRequest.End();
- if (DiagnosticUtility.ShouldTraceInformation)
- {
- TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.RequestChannelReplyReceived,
- SR.GetString(SR.TraceCodeRequestChannelReplyReceived), reply);
- }
- return reply;
- }
- finally
- {
- ReleaseRequest(asyncRequest);
- }
- }
- public Message Request(Message message)
- {
- return this.Request(message, this.DefaultSendTimeout);
- }
- public Message Request(Message message, TimeSpan timeout)
- {
- if (message == null)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("message");
- }
- if (timeout < TimeSpan.Zero)
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
- new ArgumentOutOfRangeException("timeout", timeout, SR.GetString(SR.SFxTimeoutOutOfRange0)));
- ThrowIfDisposedOrNotOpen();
- AddHeadersTo(message);
- IRequest request = CreateRequest(message);
- TrackRequest(request);
- try
- {
- Message reply;
- TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
- TimeSpan savedTimeout = timeoutHelper.RemainingTime();
- try
- {
- request.SendRequest(message, savedTimeout);
- }
- catch (TimeoutException timeoutException)
- {
- throw TraceUtility.ThrowHelperError(new TimeoutException(SR.GetString(SR.RequestChannelSendTimedOut, savedTimeout),
- timeoutException), message);
- }
- savedTimeout = timeoutHelper.RemainingTime();
- try
- {
- reply = request.WaitForReply(savedTimeout);
- }
- catch (TimeoutException timeoutException)
- {
- throw TraceUtility.ThrowHelperError(new TimeoutException(SR.GetString(SR.RequestChannelWaitForReplyTimedOut, savedTimeout),
- timeoutException), message);
- }
- if (DiagnosticUtility.ShouldTraceInformation)
- {
- TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.RequestChannelReplyReceived,
- SR.GetString(SR.TraceCodeRequestChannelReplyReceived), reply);
- }
- return reply;
- }
- finally
- {
- ReleaseRequest(request);
- }
- }
- protected virtual void AddHeadersTo(Message message)
- {
- if (!manualAddressing && to != null)
- {
- to.ApplyTo(message);
- }
- }
- class WaitForPendingRequestsAsyncResult : AsyncResult
- {
- static WaitOrTimerCallback completeWaitCallBack = new WaitOrTimerCallback(OnCompleteWaitCallBack);
- IRequestBase[] pendingRequests;
- RequestChannel requestChannel;
- TimeSpan timeout;
- RegisteredWaitHandle waitHandle;
- public WaitForPendingRequestsAsyncResult(TimeSpan timeout, RequestChannel requestChannel, IRequestBase[] pendingRequests, AsyncCallback callback, object state)
- : base(callback, state)
- {
- this.requestChannel = requestChannel;
- this.pendingRequests = pendingRequests;
- this.timeout = timeout;
- if (this.timeout == TimeSpan.Zero || this.pendingRequests == null)
- {
- AbortRequests();
- CleanupEvents();
- Complete(true);
- }
- else
- {
- this.waitHandle = ThreadPool.RegisterWaitForSingleObject(this.requestChannel.closedEvent, completeWaitCallBack, this, TimeoutHelper.ToMilliseconds(timeout), true);
- }
- }
- void AbortRequests()
- {
- if (pendingRequests != null)
- {
- foreach (IRequestBase request in pendingRequests)
- {
- request.Abort(this.requestChannel);
- }
- }
- }
- void CleanupEvents()
- {
- if (requestChannel.closedEvent != null)
- {
- if (waitHandle != null)
- {
- waitHandle.Unregister(requestChannel.closedEvent);
- }
- requestChannel.FinishClose();
- }
- }
- static void OnCompleteWaitCallBack(object state, bool timedOut)
- {
- WaitForPendingRequestsAsyncResult thisPtr = (WaitForPendingRequestsAsyncResult)state;
- Exception completionException = null;
- try
- {
- if (timedOut)
- {
- thisPtr.AbortRequests();
- }
- thisPtr.CleanupEvents();
- }
- #pragma warning suppress 56500 // [....], transferring exception to another thread
- catch (Exception e)
- {
- if (Fx.IsFatal(e))
- {
- throw;
- }
- completionException = e;
- }
- thisPtr.Complete(false, completionException);
- }
- public static void End(IAsyncResult result)
- {
- AsyncResult.End<WaitForPendingRequestsAsyncResult>(result);
- }
- }
- }
- interface IRequestBase
- {
- void Abort(RequestChannel requestChannel);
- void Fault(RequestChannel requestChannel);
- void OnReleaseRequest();
- }
- interface IRequest : IRequestBase
- {
- void SendRequest(Message message, TimeSpan timeout);
- Message WaitForReply(TimeSpan timeout);
- }
- interface IAsyncRequest : IAsyncResult, IRequestBase
- {
- void BeginSendRequest(Message message, TimeSpan timeout);
- Message End();
- }
- }
|