1 //------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation. All rights reserved.
3 //------------------------------------------------------------
5 namespace System.ServiceModel.Channels
7 using System.Collections.Generic;
9 using System.ServiceModel;
10 using System.Threading;
12 enum TolerateFaultsMode
25 All = Handled | Unhandled
28 abstract class ReliableChannelBinder<TChannel> : IReliableChannelBinder
29 where TChannel : class, IChannel
32 TimeSpan defaultCloseTimeout;
33 MaskingMode defaultMaskingMode;
34 TimeSpan defaultSendTimeout;
35 AsyncCallback onCloseChannelComplete;
36 CommunicationState state = CommunicationState.Created;
37 ChannelSynchronizer synchronizer;
38 object thisLock = new object();
40 protected ReliableChannelBinder(TChannel channel, MaskingMode maskingMode,
41 TolerateFaultsMode faultMode, TimeSpan defaultCloseTimeout,
42 TimeSpan defaultSendTimeout)
44 if ((maskingMode != MaskingMode.None) && (maskingMode != MaskingMode.All))
46 throw Fx.AssertAndThrow("ReliableChannelBinder was implemented with only 2 default masking modes, None and All.");
49 this.defaultMaskingMode = maskingMode;
50 this.defaultCloseTimeout = defaultCloseTimeout;
51 this.defaultSendTimeout = defaultSendTimeout;
53 this.synchronizer = new ChannelSynchronizer(this, channel, faultMode);
56 protected abstract bool CanGetChannelForReceive
61 public abstract bool CanSendAsynchronously
66 public virtual ChannelParameterCollection ChannelParameters
71 public IChannel Channel
75 return this.synchronizer.CurrentChannel;
83 return this.synchronizer.Connected;
87 public MaskingMode DefaultMaskingMode
91 return this.defaultMaskingMode;
95 public TimeSpan DefaultSendTimeout
99 return this.defaultSendTimeout;
103 public abstract bool HasSession
108 public abstract EndpointAddress LocalAddress
113 protected abstract bool MustCloseChannel
118 protected abstract bool MustOpenChannel
123 public abstract EndpointAddress RemoteAddress
128 public CommunicationState State
136 protected ChannelSynchronizer Synchronizer
140 return this.synchronizer;
144 protected object ThisLock
148 return this.thisLock;
156 return this.synchronizer.TolerateFaults;
160 public event EventHandler ConnectionLost;
161 public event BinderExceptionHandler Faulted;
162 public event BinderExceptionHandler OnException;
172 if (this.state == CommunicationState.Closed)
177 this.state = CommunicationState.Closing;
178 channel = this.synchronizer.StopSynchronizing(true);
180 if (!this.MustCloseChannel)
186 this.synchronizer.UnblockWaiters();
195 this.TransitionToClosed();
198 protected virtual void AddOutputHeaders(Message message)
202 public IAsyncResult BeginClose(TimeSpan timeout, AsyncCallback callback,
205 return this.BeginClose(timeout, this.defaultMaskingMode, callback, state);
208 public IAsyncResult BeginClose(TimeSpan timeout, MaskingMode maskingMode,
209 AsyncCallback callback, object state)
211 this.ThrowIfTimeoutNegative(timeout);
214 if (this.CloseCore(out channel))
216 return new CompletedAsyncResult(callback, state);
220 return new CloseAsyncResult(this, channel, timeout, maskingMode, callback, state);
224 protected virtual IAsyncResult BeginCloseChannel(TChannel channel, TimeSpan timeout,
225 AsyncCallback callback, object state)
227 return channel.BeginClose(timeout, callback, state);
230 public IAsyncResult BeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
232 this.ThrowIfTimeoutNegative(timeout);
234 if (this.OnOpening(this.defaultMaskingMode))
238 return this.OnBeginOpen(timeout, callback, state);
249 if (this.defaultMaskingMode == MaskingMode.None)
255 this.RaiseOnException(e);
260 return new BinderCompletedAsyncResult(callback, state);
263 public IAsyncResult BeginSend(Message message, TimeSpan timeout, AsyncCallback callback,
266 return this.BeginSend(message, timeout, this.defaultMaskingMode, callback, state);
269 public IAsyncResult BeginSend(Message message, TimeSpan timeout, MaskingMode maskingMode,
270 AsyncCallback callback, object state)
272 SendAsyncResult result = new SendAsyncResult(this, callback, state);
273 result.Start(message, timeout, maskingMode);
277 // ChannelSynchronizer helper, cannot take a lock.
278 protected abstract IAsyncResult BeginTryGetChannel(TimeSpan timeout,
279 AsyncCallback callback, object state);
281 public virtual IAsyncResult BeginTryReceive(TimeSpan timeout, AsyncCallback callback,
284 return this.BeginTryReceive(timeout, this.defaultMaskingMode, callback, state);
287 public virtual IAsyncResult BeginTryReceive(TimeSpan timeout, MaskingMode maskingMode,
288 AsyncCallback callback, object state)
290 if (this.ValidateInputOperation(timeout))
291 return new TryReceiveAsyncResult(this, timeout, maskingMode, callback, state);
293 return new CompletedAsyncResult(callback, state);
296 internal IAsyncResult BeginWaitForPendingOperations(TimeSpan timeout,
297 AsyncCallback callback, object state)
299 return this.synchronizer.BeginWaitForPendingOperations(timeout, callback, state);
302 bool CloseCore(out TChannel channel)
306 bool abortChannel = false;
310 if ((this.state == CommunicationState.Closing)
311 || (this.state == CommunicationState.Closed))
316 if (this.state == CommunicationState.Opened)
318 this.state = CommunicationState.Closing;
319 channel = this.synchronizer.StopSynchronizing(true);
322 if (!this.MustCloseChannel)
329 CommunicationState channelState = channel.State;
331 if ((channelState == CommunicationState.Created)
332 || (channelState == CommunicationState.Opening)
333 || (channelState == CommunicationState.Faulted))
337 else if ((channelState == CommunicationState.Closing)
338 || (channelState == CommunicationState.Closed))
346 this.synchronizer.UnblockWaiters();
365 public void Close(TimeSpan timeout)
367 this.Close(timeout, this.defaultMaskingMode);
370 public void Close(TimeSpan timeout, MaskingMode maskingMode)
372 this.ThrowIfTimeoutNegative(timeout);
373 TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
376 if (this.CloseCore(out channel))
384 this.OnClose(timeoutHelper.RemainingTime());
388 this.CloseChannel(channel, timeoutHelper.RemainingTime());
391 this.TransitionToClosed();
402 if (!this.HandleException(e, maskingMode))
409 // The ChannelSynchronizer calls this from an operation thread so this method must not
411 void CloseChannel(TChannel channel)
413 if (!this.MustCloseChannel)
415 throw Fx.AssertAndThrow("MustCloseChannel is false when there is no receive loop and this method is called when there is a receive loop.");
418 if (this.onCloseChannelComplete == null)
420 this.onCloseChannelComplete = Fx.ThunkCallback(new AsyncCallback(this.OnCloseChannelComplete));
425 IAsyncResult result = channel.BeginClose(onCloseChannelComplete, channel);
427 if (result.CompletedSynchronously)
429 channel.EndClose(result);
432 #pragma warning suppress 56500 // covered by FxCOP
440 this.HandleException(e, MaskingMode.All);
444 protected virtual void CloseChannel(TChannel channel, TimeSpan timeout)
446 channel.Close(timeout);
449 public void EndClose(IAsyncResult result)
451 CloseAsyncResult closeResult = result as CloseAsyncResult;
453 if (closeResult != null)
459 CompletedAsyncResult.End(result);
463 protected virtual void EndCloseChannel(TChannel channel, IAsyncResult result)
465 channel.EndClose(result);
468 public void EndOpen(IAsyncResult result)
470 BinderCompletedAsyncResult completedResult = result as BinderCompletedAsyncResult;
472 if (completedResult != null)
474 completedResult.End();
480 this.OnEndOpen(result);
491 if (this.defaultMaskingMode == MaskingMode.None)
497 this.RaiseOnException(e);
502 this.synchronizer.StartSynchronizing();
507 public void EndSend(IAsyncResult result)
509 SendAsyncResult.End(result);
512 // ChannelSynchronizer helper, cannot take a lock.
513 protected abstract bool EndTryGetChannel(IAsyncResult result);
515 public virtual bool EndTryReceive(IAsyncResult result, out RequestContext requestContext)
517 TryReceiveAsyncResult tryReceiveResult = result as TryReceiveAsyncResult;
519 if (tryReceiveResult != null)
521 return tryReceiveResult.End(out requestContext);
525 CompletedAsyncResult.End(result);
526 requestContext = null;
531 public void EndWaitForPendingOperations(IAsyncResult result)
533 this.synchronizer.EndWaitForPendingOperations(result);
536 protected void Fault(Exception e)
540 if (this.state == CommunicationState.Created)
542 throw Fx.AssertAndThrow("The binder should not detect the inner channel's faults until after the binder is opened.");
545 if ((this.state == CommunicationState.Faulted)
546 || (this.state == CommunicationState.Closed))
551 this.state = CommunicationState.Faulted;
552 this.synchronizer.StopSynchronizing(false);
555 this.synchronizer.UnblockWaiters();
557 BinderExceptionHandler handler = this.Faulted;
565 // ChannelSynchronizer helper, cannot take a lock.
566 Exception GetClosedException(MaskingMode maskingMode)
568 if (ReliableChannelBinderHelper.MaskHandled(maskingMode))
572 else if (this.aborted)
574 return new CommunicationObjectAbortedException(SR.GetString(
575 SR.CommunicationObjectAborted1, this.GetType().ToString()));
579 return new ObjectDisposedException(this.GetType().ToString());
583 // Must be called within lock (this.ThisLock)
584 Exception GetClosedOrFaultedException(MaskingMode maskingMode)
586 if (this.state == CommunicationState.Faulted)
588 return this.GetFaultedException(maskingMode);
590 else if ((this.state == CommunicationState.Closing)
591 || (this.state == CommunicationState.Closed))
593 return this.GetClosedException(maskingMode);
597 throw Fx.AssertAndThrow("Caller is attempting to get a terminal exception in a non-terminal state.");
601 // ChannelSynchronizer helper, cannot take a lock.
602 Exception GetFaultedException(MaskingMode maskingMode)
604 if (ReliableChannelBinderHelper.MaskHandled(maskingMode))
610 return new CommunicationObjectFaultedException(SR.GetString(
611 SR.CommunicationObjectFaulted1, this.GetType().ToString()));
615 public abstract ISession GetInnerSession();
617 public void HandleException(Exception e)
619 this.HandleException(e, MaskingMode.All);
622 protected bool HandleException(Exception e, MaskingMode maskingMode)
624 if (this.TolerateFaults && (e is CommunicationObjectFaultedException))
629 if (this.IsHandleable(e))
631 return ReliableChannelBinderHelper.MaskHandled(maskingMode);
634 bool maskUnhandled = ReliableChannelBinderHelper.MaskUnhandled(maskingMode);
638 this.RaiseOnException(e);
641 return maskUnhandled;
644 protected bool HandleException(Exception e, MaskingMode maskingMode, bool autoAborted)
646 if (this.TolerateFaults && autoAborted && e is CommunicationObjectAbortedException)
651 return this.HandleException(e, maskingMode);
654 // ChannelSynchronizer helper, cannot take a lock.
655 protected abstract bool HasSecuritySession(TChannel channel);
657 public bool IsHandleable(Exception e)
659 if (e is ProtocolException)
664 return (e is CommunicationException)
665 || (e is TimeoutException);
668 protected abstract void OnAbort();
669 protected abstract IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback callback,
671 protected abstract IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback,
674 protected virtual IAsyncResult OnBeginSend(TChannel channel, Message message,
675 TimeSpan timeout, AsyncCallback callback, object state)
677 throw Fx.AssertAndThrow("The derived class does not support the BeginSend operation.");
680 protected virtual IAsyncResult OnBeginTryReceive(TChannel channel, TimeSpan timeout,
681 AsyncCallback callback, object state)
683 throw Fx.AssertAndThrow("The derived class does not support the BeginTryReceive operation.");
686 protected abstract void OnClose(TimeSpan timeout);
688 void OnCloseChannelComplete(IAsyncResult result)
690 if (result.CompletedSynchronously)
695 TChannel channel = (TChannel)result.AsyncState;
699 channel.EndClose(result);
701 #pragma warning suppress 56500 // covered by FxCOP
709 this.HandleException(e, MaskingMode.All);
713 protected abstract void OnEndClose(IAsyncResult result);
714 protected abstract void OnEndOpen(IAsyncResult result);
716 protected virtual void OnEndSend(TChannel channel, IAsyncResult result)
718 throw Fx.AssertAndThrow("The derived class does not support the EndSend operation.");
721 protected virtual bool OnEndTryReceive(TChannel channel, IAsyncResult result,
722 out RequestContext requestContext)
724 throw Fx.AssertAndThrow("The derived class does not support the EndTryReceive operation.");
727 void OnInnerChannelFaulted()
729 if (!this.TolerateFaults)
732 EventHandler handler = this.ConnectionLost;
735 handler(this, EventArgs.Empty);
738 protected abstract void OnOpen(TimeSpan timeout);
744 if (this.state == CommunicationState.Opening)
746 this.state = CommunicationState.Opened;
751 bool OnOpening(MaskingMode maskingMode)
755 if (this.state != CommunicationState.Created)
759 if ((this.state == CommunicationState.Opening)
760 || (this.state == CommunicationState.Opened))
762 if (!ReliableChannelBinderHelper.MaskUnhandled(maskingMode))
764 e = new InvalidOperationException(SR.GetString(
765 SR.CommunicationObjectCannotBeModifiedInState,
766 this.GetType().ToString(), this.state.ToString()));
771 e = this.GetClosedOrFaultedException(maskingMode);
776 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(e);
783 this.state = CommunicationState.Opening;
789 protected virtual void OnShutdown()
793 protected virtual void OnSend(TChannel channel, Message message, TimeSpan timeout)
795 throw Fx.AssertAndThrow("The derived class does not support the Send operation.");
798 protected virtual bool OnTryReceive(TChannel channel, TimeSpan timeout,
799 out RequestContext requestContext)
801 throw Fx.AssertAndThrow("The derived class does not support the TryReceive operation.");
804 public void Open(TimeSpan timeout)
806 this.ThrowIfTimeoutNegative(timeout);
808 if (!this.OnOpening(this.defaultMaskingMode))
815 this.OnOpen(timeout);
826 if (this.defaultMaskingMode == MaskingMode.None)
832 this.RaiseOnException(e);
837 this.synchronizer.StartSynchronizing();
841 void RaiseOnException(Exception e)
843 BinderExceptionHandler handler = this.OnException;
851 public void Send(Message message, TimeSpan timeout)
853 this.Send(message, timeout, this.defaultMaskingMode);
856 public void Send(Message message, TimeSpan timeout, MaskingMode maskingMode)
858 if (!this.ValidateOutputOperation(message, timeout, maskingMode))
863 bool autoAborted = false;
867 TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
870 if (!this.synchronizer.TryGetChannelForOutput(timeoutHelper.RemainingTime(), maskingMode,
873 if (!ReliableChannelBinderHelper.MaskHandled(maskingMode))
875 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
876 new TimeoutException(SR.GetString(SR.TimeoutOnSend, timeout)));
887 this.AddOutputHeaders(message);
891 this.OnSend(channel, message, timeoutHelper.RemainingTime());
895 autoAborted = this.Synchronizer.Aborting;
896 this.synchronizer.ReturnChannel();
906 if (!this.HandleException(e, maskingMode, autoAborted))
913 public void SetMaskingMode(RequestContext context, MaskingMode maskingMode)
915 BinderRequestContext binderContext = (BinderRequestContext)context;
916 binderContext.SetMaskingMode(maskingMode);
919 // throwDisposed indicates whether to throw in the Faulted, Closing, and Closed states.
920 // returns true if in Opened state
921 bool ThrowIfNotOpenedAndNotMasking(MaskingMode maskingMode, bool throwDisposed)
925 if (this.State == CommunicationState.Created)
927 throw Fx.AssertAndThrow("Messaging operations cannot be called when the binder is in the Created state.");
930 if (this.State == CommunicationState.Opening)
932 throw Fx.AssertAndThrow("Messaging operations cannot be called when the binder is in the Opening state.");
935 if (this.State == CommunicationState.Opened)
940 // state is Faulted, Closing, or Closed
943 Exception e = this.GetClosedOrFaultedException(maskingMode);
947 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(e);
955 void ThrowIfTimeoutNegative(TimeSpan timeout)
957 if (timeout < TimeSpan.Zero)
959 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
960 new ArgumentOutOfRangeException("timeout", timeout, SR.SFxTimeoutOutOfRange0));
964 void TransitionToClosed()
968 if ((this.state != CommunicationState.Closing)
969 && (this.state != CommunicationState.Closed)
970 && (this.state != CommunicationState.Faulted))
972 throw Fx.AssertAndThrow("Caller cannot transition to the Closed state from a non-terminal state.");
975 this.state = CommunicationState.Closed;
979 // ChannelSynchronizer helper, cannot take a lock.
980 protected abstract bool TryGetChannel(TimeSpan timeout);
982 public virtual bool TryReceive(TimeSpan timeout, out RequestContext requestContext)
984 return this.TryReceive(timeout, out requestContext, this.defaultMaskingMode);
987 public virtual bool TryReceive(TimeSpan timeout, out RequestContext requestContext, MaskingMode maskingMode)
989 if (maskingMode != MaskingMode.None)
991 throw Fx.AssertAndThrow("This method was implemented only for the case where we do not mask exceptions.");
994 if (!this.ValidateInputOperation(timeout))
996 requestContext = null;
1000 TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
1004 bool autoAborted = false;
1009 bool success = !this.synchronizer.TryGetChannelForInput(
1010 this.CanGetChannelForReceive, timeoutHelper.RemainingTime(), out channel);
1012 if (channel == null)
1014 requestContext = null;
1020 success = this.OnTryReceive(channel, timeoutHelper.RemainingTime(),
1021 out requestContext);
1023 // timed out || got message, return immediately
1024 if (!success || (requestContext != null))
1029 // the underlying channel closed or faulted, retry
1030 this.synchronizer.OnReadEof();
1034 autoAborted = this.Synchronizer.Aborting;
1035 this.synchronizer.ReturnChannel();
1045 if (!this.HandleException(e, maskingMode, autoAborted))
1053 protected bool ValidateInputOperation(TimeSpan timeout)
1055 if (timeout < TimeSpan.Zero)
1057 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("timeout", timeout,
1058 SR.SFxTimeoutOutOfRange0));
1061 return this.ThrowIfNotOpenedAndNotMasking(MaskingMode.All, false);
1064 protected bool ValidateOutputOperation(Message message, TimeSpan timeout, MaskingMode maskingMode)
1066 if (message == null)
1068 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("message");
1071 if (timeout < TimeSpan.Zero)
1073 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("timeout", timeout,
1074 SR.SFxTimeoutOutOfRange0));
1077 return this.ThrowIfNotOpenedAndNotMasking(maskingMode, true);
1080 internal void WaitForPendingOperations(TimeSpan timeout)
1082 this.synchronizer.WaitForPendingOperations(timeout);
1085 protected RequestContext WrapMessage(Message message)
1087 if (message == null)
1092 return new MessageRequestContext(this, message);
1095 public RequestContext WrapRequestContext(RequestContext context)
1097 if (context == null)
1102 if (!this.TolerateFaults && this.defaultMaskingMode == MaskingMode.None)
1107 return new RequestRequestContext(this, context, context.RequestMessage);
1110 sealed class BinderCompletedAsyncResult : CompletedAsyncResult
1112 public BinderCompletedAsyncResult(AsyncCallback callback, object state)
1113 : base(callback, state)
1119 CompletedAsyncResult.End(this);
1123 abstract class BinderRequestContext : RequestContextBase
1125 ReliableChannelBinder<TChannel> binder;
1126 MaskingMode maskingMode;
1128 public BinderRequestContext(ReliableChannelBinder<TChannel> binder, Message message)
1129 : base(message, binder.defaultCloseTimeout, binder.defaultSendTimeout)
1133 Fx.Assert("Argument binder cannot be null.");
1136 this.binder = binder;
1137 this.maskingMode = binder.defaultMaskingMode;
1140 protected ReliableChannelBinder<TChannel> Binder
1148 protected MaskingMode MaskingMode
1152 return this.maskingMode;
1156 public void SetMaskingMode(MaskingMode maskingMode)
1158 if (this.binder.defaultMaskingMode != MaskingMode.All)
1160 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException());
1163 this.maskingMode = maskingMode;
1167 protected class ChannelSynchronizer
1169 bool aborting; // Indicates the current channel is being aborted, not the synchronizer.
1170 ReliableChannelBinder<TChannel> binder;
1172 TChannel currentChannel;
1173 InterruptibleWaitObject drainEvent;
1174 static Action<object> asyncGetChannelCallback = new Action<object>(AsyncGetChannelCallback);
1175 TolerateFaultsMode faultMode;
1176 Queue<IWaiter> getChannelQueue;
1177 bool innerChannelFaulted;
1178 EventHandler onChannelFaulted;
1179 State state = State.Created;
1180 bool tolerateFaults = true;
1181 object thisLock = new object();
1182 Queue<IWaiter> waitQueue;
1184 public ChannelSynchronizer(ReliableChannelBinder<TChannel> binder, TChannel channel,
1185 TolerateFaultsMode faultMode)
1187 this.binder = binder;
1188 this.currentChannel = channel;
1189 this.faultMode = faultMode;
1192 public bool Aborting
1196 return this.aborting;
1200 public bool Connected
1204 return (this.state == State.ChannelOpened ||
1205 this.state == State.ChannelOpening);
1209 public TChannel CurrentChannel
1213 return this.currentChannel;
1221 return this.thisLock;
1225 public bool TolerateFaults
1229 return this.tolerateFaults;
1234 public TChannel AbortCurentChannel()
1236 lock (this.ThisLock)
1238 if (!this.tolerateFaults)
1240 throw Fx.AssertAndThrow("It is only valid to abort the current channel when masking faults");
1243 if (this.state == State.ChannelOpening)
1245 this.aborting = true;
1247 else if (this.state == State.ChannelOpened)
1249 if (this.count == 0)
1251 this.state = State.NoChannel;
1255 this.aborting = true;
1256 this.state = State.ChannelClosing;
1264 return this.currentChannel;
1268 static void AsyncGetChannelCallback(object state)
1270 AsyncWaiter waiter = (AsyncWaiter)state;
1271 waiter.GetChannel(false);
1274 public IAsyncResult BeginTryGetChannelForInput(bool canGetChannel, TimeSpan timeout,
1275 AsyncCallback callback, object state)
1277 return this.BeginTryGetChannel(canGetChannel, false, timeout, MaskingMode.All,
1281 public IAsyncResult BeginTryGetChannelForOutput(TimeSpan timeout,
1282 MaskingMode maskingMode, AsyncCallback callback, object state)
1284 return this.BeginTryGetChannel(true, true, timeout, maskingMode,
1288 IAsyncResult BeginTryGetChannel(bool canGetChannel, bool canCauseFault,
1289 TimeSpan timeout, MaskingMode maskingMode, AsyncCallback callback, object state)
1291 TChannel channel = null;
1292 AsyncWaiter waiter = null;
1293 bool getChannel = false;
1294 bool faulted = false;
1296 lock (this.ThisLock)
1298 if (!this.ThrowIfNecessary(maskingMode))
1302 else if (this.state == State.ChannelOpened)
1304 if (this.currentChannel == null)
1306 throw Fx.AssertAndThrow("Field currentChannel cannot be null in the ChannelOpened state.");
1310 channel = this.currentChannel;
1312 else if (!this.tolerateFaults
1313 && ((this.state == State.NoChannel)
1314 || (this.state == State.ChannelClosing)))
1323 else if (!canGetChannel
1324 || (this.state == State.ChannelOpening)
1325 || (this.state == State.ChannelClosing))
1327 waiter = new AsyncWaiter(this, canGetChannel, null, timeout, maskingMode,
1328 this.binder.ChannelParameters,
1330 this.GetQueue(canGetChannel).Enqueue(waiter);
1334 if (this.state != State.NoChannel)
1336 throw Fx.AssertAndThrow("The state must be NoChannel.");
1339 waiter = new AsyncWaiter(this, canGetChannel,
1340 this.GetCurrentChannelIfCreated(), timeout, maskingMode,
1341 this.binder.ChannelParameters,
1344 this.state = State.ChannelOpening;
1351 this.binder.Fault(null);
1356 return new CompletedAsyncResult<TChannel>(channel, callback, state);
1361 waiter.GetChannel(true);
1371 public IAsyncResult BeginWaitForPendingOperations(TimeSpan timeout,
1372 AsyncCallback callback, object state)
1374 lock (this.ThisLock)
1376 if (this.drainEvent != null)
1378 throw Fx.AssertAndThrow("The WaitForPendingOperations operation may only be invoked once.");
1383 this.drainEvent = new InterruptibleWaitObject(false, false);
1387 if (this.drainEvent != null)
1389 return this.drainEvent.BeginWait(timeout, callback, state);
1393 return new SynchronizerCompletedAsyncResult(callback, state);
1397 bool CompleteSetChannel(IWaiter waiter, out TChannel channel)
1401 throw Fx.AssertAndThrow("Argument waiter cannot be null.");
1406 lock (this.ThisLock)
1408 if (this.ValidateOpened())
1410 channel = this.currentChannel;
1416 close = this.state == State.Closed;
1432 public bool EndTryGetChannel(IAsyncResult result, out TChannel channel)
1434 AsyncWaiter waiter = result as AsyncWaiter;
1438 return waiter.End(out channel);
1442 channel = CompletedAsyncResult<TChannel>.End(result);
1447 public void EndWaitForPendingOperations(IAsyncResult result)
1449 SynchronizerCompletedAsyncResult completedResult =
1450 result as SynchronizerCompletedAsyncResult;
1452 if (completedResult != null)
1454 completedResult.End();
1458 this.drainEvent.EndWait(result);
1463 public bool EnsureChannel()
1467 lock (this.ThisLock)
1469 if (this.ValidateOpened())
1471 // This is called only during the RM CS phase. In this phase, there are 2
1472 // valid states between Request calls, ChannelOpened and NoChannel.
1473 if (this.state == State.ChannelOpened)
1478 if (this.state != State.NoChannel)
1480 throw Fx.AssertAndThrow("The caller may only invoke this EnsureChannel during the CreateSequence negotiation. ChannelOpening and ChannelClosing are invalid states during this phase of the negotiation.");
1483 if (!this.tolerateFaults)
1489 if (this.GetCurrentChannelIfCreated() != null)
1494 if (this.binder.TryGetChannel(TimeSpan.Zero))
1496 if (this.currentChannel == null)
1509 this.binder.Fault(null);
1515 IWaiter GetChannelWaiter()
1517 if ((this.getChannelQueue == null) || (this.getChannelQueue.Count == 0))
1522 return this.getChannelQueue.Dequeue();
1525 // Must be called within lock (this.ThisLock)
1526 TChannel GetCurrentChannelIfCreated()
1528 if (this.state != State.NoChannel)
1530 throw Fx.AssertAndThrow("This method may only be called in the NoChannel state.");
1533 if ((this.currentChannel != null)
1534 && (this.currentChannel.State == CommunicationState.Created))
1536 return this.currentChannel;
1544 Queue<IWaiter> GetQueue(bool canGetChannel)
1548 if (this.getChannelQueue == null)
1550 this.getChannelQueue = new Queue<IWaiter>();
1553 return this.getChannelQueue;
1557 if (this.waitQueue == null)
1559 this.waitQueue = new Queue<IWaiter>();
1562 return this.waitQueue;
1566 void OnChannelFaulted(object sender, EventArgs e)
1568 TChannel faultedChannel = (TChannel)sender;
1569 bool faultBinder = false;
1570 bool raiseInnerChannelFaulted = false;
1572 lock (this.ThisLock)
1574 if (this.currentChannel != faultedChannel)
1579 // The synchronizer is already closed or aborted.
1580 if (!this.ValidateOpened())
1585 if (this.state == State.ChannelOpened)
1587 if (this.count == 0)
1589 faultedChannel.Faulted -= this.onChannelFaulted;
1592 faultBinder = !this.tolerateFaults;
1593 this.state = State.ChannelClosing;
1594 this.innerChannelFaulted = true;
1596 if (!faultBinder && this.count == 0)
1598 this.state = State.NoChannel;
1599 this.aborting = false;
1600 raiseInnerChannelFaulted = true;
1601 this.innerChannelFaulted = false;
1608 this.binder.Fault(null);
1611 faultedChannel.Abort();
1613 if (raiseInnerChannelFaulted)
1615 this.binder.OnInnerChannelFaulted();
1619 bool OnChannelOpened(IWaiter waiter)
1623 throw Fx.AssertAndThrow("Argument waiter cannot be null.");
1629 Queue<IWaiter> temp1 = null;
1630 Queue<IWaiter> temp2 = null;
1631 TChannel channel = null;
1633 lock (this.ThisLock)
1635 if (this.currentChannel == null)
1637 throw Fx.AssertAndThrow("Caller must ensure that field currentChannel is set before opening the channel.");
1640 if (this.ValidateOpened())
1642 if (this.state != State.ChannelOpening)
1644 throw Fx.AssertAndThrow("This method may only be called in the ChannelOpening state.");
1647 this.state = State.ChannelOpened;
1648 this.SetTolerateFaults();
1651 this.count += (this.getChannelQueue == null) ? 0 : this.getChannelQueue.Count;
1652 this.count += (this.waitQueue == null) ? 0 : this.waitQueue.Count;
1654 temp1 = this.getChannelQueue;
1655 temp2 = this.waitQueue;
1656 channel = this.currentChannel;
1658 this.getChannelQueue = null;
1659 this.waitQueue = null;
1663 close = this.state == State.Closed;
1664 fault = this.state == State.Faulted;
1679 this.SetWaiters(temp1, channel);
1680 this.SetWaiters(temp2, channel);
1684 void OnGetChannelFailed()
1686 IWaiter waiter = null;
1688 lock (this.ThisLock)
1690 if (!this.ValidateOpened())
1695 if (this.state != State.ChannelOpening)
1697 throw Fx.AssertAndThrow("The state must be set to ChannelOpening before the caller attempts to open the channel.");
1700 waiter = this.GetChannelWaiter();
1704 this.state = State.NoChannel;
1709 if (waiter is SyncWaiter)
1711 waiter.GetChannel(false);
1715 ActionItem.Schedule(asyncGetChannelCallback, waiter);
1719 public void OnReadEof()
1721 lock (this.ThisLock)
1723 if (this.count <= 0)
1725 throw Fx.AssertAndThrow("Caller must ensure that OnReadEof is called before ReturnChannel.");
1728 if (this.ValidateOpened())
1730 if ((this.state != State.ChannelOpened) && (this.state != State.ChannelClosing))
1732 throw Fx.AssertAndThrow("Since count is positive, the only valid states are ChannelOpened and ChannelClosing.");
1735 if (this.currentChannel.State != CommunicationState.Faulted)
1737 this.state = State.ChannelClosing;
1743 bool RemoveWaiter(IWaiter waiter)
1745 Queue<IWaiter> waiters = waiter.CanGetChannel ? this.getChannelQueue : this.waitQueue;
1747 if (waiters == null)
1752 bool removed = false;
1754 lock (this.ThisLock)
1756 if (!this.ValidateOpened())
1761 for (int i = waiters.Count; i > 0; i--)
1763 IWaiter temp = waiters.Dequeue();
1765 if (object.ReferenceEquals(waiter, temp))
1771 waiters.Enqueue(temp);
1779 public void ReturnChannel()
1781 TChannel channel = null;
1782 IWaiter waiter = null;
1783 bool faultBinder = false;
1785 bool raiseInnerChannelFaulted = false;
1787 lock (this.ThisLock)
1789 if (this.count <= 0)
1791 throw Fx.AssertAndThrow("Method ReturnChannel() can only be called after TryGetChannel or EndTryGetChannel returns a channel.");
1795 drained = (this.count == 0) && (this.drainEvent != null);
1797 if (this.ValidateOpened())
1799 if ((this.state != State.ChannelOpened) && (this.state != State.ChannelClosing))
1801 throw Fx.AssertAndThrow("ChannelOpened and ChannelClosing are the only 2 valid states when count is positive.");
1804 if (this.currentChannel.State == CommunicationState.Faulted)
1806 faultBinder = !this.tolerateFaults;
1807 this.innerChannelFaulted = true;
1808 this.state = State.ChannelClosing;
1811 if (!faultBinder && (this.state == State.ChannelClosing) && (this.count == 0))
1813 channel = this.currentChannel;
1814 raiseInnerChannelFaulted = this.innerChannelFaulted;
1815 this.innerChannelFaulted = false;
1817 this.state = State.NoChannel;
1818 this.aborting = false;
1820 waiter = this.GetChannelWaiter();
1824 this.state = State.ChannelOpening;
1832 this.binder.Fault(null);
1837 this.drainEvent.Set();
1840 if (channel != null)
1842 channel.Faulted -= this.onChannelFaulted;
1844 if (channel.State == CommunicationState.Opened)
1846 this.binder.CloseChannel(channel);
1855 waiter.GetChannel(false);
1859 if (raiseInnerChannelFaulted)
1861 this.binder.OnInnerChannelFaulted();
1865 public bool SetChannel(TChannel channel)
1867 lock (this.ThisLock)
1869 if (this.state != State.ChannelOpening && this.state != State.NoChannel)
1871 throw Fx.AssertAndThrow("SetChannel is only valid in the NoChannel and ChannelOpening states");
1874 if (!this.tolerateFaults)
1876 throw Fx.AssertAndThrow("SetChannel is only valid when masking faults");
1879 if (this.ValidateOpened())
1881 this.currentChannel = channel;
1891 void SetTolerateFaults()
1893 if (this.faultMode == TolerateFaultsMode.Never)
1895 this.tolerateFaults = false;
1897 else if (this.faultMode == TolerateFaultsMode.IfNotSecuritySession)
1899 this.tolerateFaults = !this.binder.HasSecuritySession(this.currentChannel);
1902 if (this.onChannelFaulted == null)
1904 this.onChannelFaulted = new EventHandler(this.OnChannelFaulted);
1907 this.currentChannel.Faulted += this.onChannelFaulted;
1910 void SetWaiters(Queue<IWaiter> waiters, TChannel channel)
1912 if ((waiters != null) && (waiters.Count > 0))
1914 foreach (IWaiter waiter in waiters)
1916 waiter.Set(channel);
1921 public void StartSynchronizing()
1923 lock (this.ThisLock)
1925 if (this.state == State.Created)
1927 this.state = State.NoChannel;
1931 if (this.state != State.Closed)
1933 throw Fx.AssertAndThrow("Abort is the only operation that can ---- with Open.");
1939 if (this.currentChannel == null)
1941 if (!this.binder.TryGetChannel(TimeSpan.Zero))
1947 if (this.currentChannel == null)
1952 if (!this.binder.MustOpenChannel)
1954 // Channel is already opened.
1955 this.state = State.ChannelOpened;
1956 this.SetTolerateFaults();
1961 public TChannel StopSynchronizing(bool close)
1963 lock (this.ThisLock)
1965 if ((this.state != State.Faulted) && (this.state != State.Closed))
1967 this.state = close ? State.Closed : State.Faulted;
1969 if ((this.currentChannel != null) && (this.onChannelFaulted != null))
1971 this.currentChannel.Faulted -= this.onChannelFaulted;
1975 return this.currentChannel;
1979 // Must be called under a lock.
1980 bool ThrowIfNecessary(MaskingMode maskingMode)
1982 if (this.ValidateOpened())
1987 // state is Closed or Faulted.
1990 if (this.state == State.Closed)
1992 e = this.binder.GetClosedException(maskingMode);
1996 e = this.binder.GetFaultedException(maskingMode);
2001 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(e);
2007 public bool TryGetChannelForInput(bool canGetChannel, TimeSpan timeout,
2008 out TChannel channel)
2010 return this.TryGetChannel(canGetChannel, false, timeout, MaskingMode.All,
2014 public bool TryGetChannelForOutput(TimeSpan timeout, MaskingMode maskingMode,
2015 out TChannel channel)
2017 return this.TryGetChannel(true, true, timeout, maskingMode, out channel);
2020 bool TryGetChannel(bool canGetChannel, bool canCauseFault, TimeSpan timeout,
2021 MaskingMode maskingMode, out TChannel channel)
2023 SyncWaiter waiter = null;
2024 bool faulted = false;
2025 bool getChannel = false;
2027 lock (this.ThisLock)
2029 if (!this.ThrowIfNecessary(maskingMode))
2035 if (this.state == State.ChannelOpened)
2037 if (this.currentChannel == null)
2039 throw Fx.AssertAndThrow("Field currentChannel cannot be null in the ChannelOpened state.");
2043 channel = this.currentChannel;
2047 if (!this.tolerateFaults
2048 && ((this.state == State.ChannelClosing)
2049 || (this.state == State.NoChannel)))
2059 else if (!canGetChannel
2060 || (this.state == State.ChannelOpening)
2061 || (this.state == State.ChannelClosing))
2063 waiter = new SyncWaiter(this, canGetChannel, null, timeout, maskingMode, this.binder.ChannelParameters);
2064 this.GetQueue(canGetChannel).Enqueue(waiter);
2068 if (this.state != State.NoChannel)
2070 throw Fx.AssertAndThrow("The state must be NoChannel.");
2073 waiter = new SyncWaiter(this, canGetChannel,
2074 this.GetCurrentChannelIfCreated(), timeout, maskingMode,
2075 this.binder.ChannelParameters);
2077 this.state = State.ChannelOpening;
2084 this.binder.Fault(null);
2091 waiter.GetChannel(true);
2094 return waiter.TryWait(out channel);
2097 public void UnblockWaiters()
2099 Queue<IWaiter> temp1;
2100 Queue<IWaiter> temp2;
2102 lock (this.ThisLock)
2104 temp1 = this.getChannelQueue;
2105 temp2 = this.waitQueue;
2107 this.getChannelQueue = null;
2108 this.waitQueue = null;
2111 bool close = this.state == State.Closed;
2112 this.UnblockWaiters(temp1, close);
2113 this.UnblockWaiters(temp2, close);
2116 void UnblockWaiters(Queue<IWaiter> waiters, bool close)
2118 if ((waiters != null) && (waiters.Count > 0))
2120 foreach (IWaiter waiter in waiters)
2134 bool ValidateOpened()
2136 if (this.state == State.Created)
2138 throw Fx.AssertAndThrow("This operation expects that the synchronizer has been opened.");
2141 return (this.state != State.Closed) && (this.state != State.Faulted);
2144 public void WaitForPendingOperations(TimeSpan timeout)
2146 lock (this.ThisLock)
2148 if (this.drainEvent != null)
2150 throw Fx.AssertAndThrow("The WaitForPendingOperations operation may only be invoked once.");
2155 this.drainEvent = new InterruptibleWaitObject(false, false);
2159 if (this.drainEvent != null)
2161 this.drainEvent.Wait(timeout);
2176 public interface IWaiter
2178 bool CanGetChannel { get; }
2182 void GetChannel(bool onUserThread);
2183 void Set(TChannel channel);
2186 public sealed class AsyncWaiter : AsyncResult, IWaiter
2190 ChannelParameterCollection channelParameters;
2191 bool isSynchronous = true;
2192 MaskingMode maskingMode;
2193 static AsyncCallback onOpenComplete = Fx.ThunkCallback(new AsyncCallback(OnOpenComplete));
2194 static Action<object> onTimeoutElapsed = new Action<object>(OnTimeoutElapsed);
2195 static AsyncCallback onTryGetChannelComplete = Fx.ThunkCallback(new AsyncCallback(OnTryGetChannelComplete));
2196 bool timedOut = false;
2197 ChannelSynchronizer synchronizer;
2198 TimeoutHelper timeoutHelper;
2199 IOThreadTimer timer;
2200 bool timerCancelled = false;
2202 public AsyncWaiter(ChannelSynchronizer synchronizer, bool canGetChannel,
2203 TChannel channel, TimeSpan timeout, MaskingMode maskingMode,
2204 ChannelParameterCollection channelParameters,
2205 AsyncCallback callback, object state)
2206 : base(callback, state)
2210 if (channel != null)
2212 throw Fx.AssertAndThrow("This waiter must wait for a channel thus argument channel must be null.");
2216 this.synchronizer = synchronizer;
2217 this.canGetChannel = canGetChannel;
2218 this.channel = channel;
2219 this.timeoutHelper = new TimeoutHelper(timeout);
2220 this.maskingMode = maskingMode;
2221 this.channelParameters = channelParameters;
2224 public bool CanGetChannel
2228 return this.canGetChannel;
2242 lock (this.ThisLock)
2244 if (!this.timerCancelled)
2246 if (this.timer != null)
2248 this.timer.Cancel();
2251 this.timerCancelled = true;
2259 this.channel = null;
2260 this.Complete(false,
2261 this.synchronizer.binder.GetClosedException(this.maskingMode));
2264 bool CompleteOpen(IAsyncResult result)
2266 this.channel.EndOpen(result);
2267 return this.OnChannelOpened();
2270 bool CompleteTryGetChannel(IAsyncResult result)
2272 if (!this.synchronizer.binder.EndTryGetChannel(result))
2274 this.timedOut = true;
2275 this.OnGetChannelFailed();
2279 if (!this.synchronizer.CompleteSetChannel(this, out this.channel))
2281 if (!this.IsCompleted)
2283 throw Fx.AssertAndThrow("CompleteSetChannel must complete the IWaiter if it returns false.");
2289 return this.OpenChannel();
2292 public bool End(out TChannel channel)
2294 AsyncResult.End<AsyncWaiter>(this);
2295 channel = this.channel;
2296 return !this.timedOut;
2302 this.channel = null;
2303 this.Complete(false,
2304 this.synchronizer.binder.GetFaultedException(this.maskingMode));
2309 if (this.channel != null)
2311 return this.OpenChannel();
2315 IAsyncResult result = this.synchronizer.binder.BeginTryGetChannel(
2316 this.timeoutHelper.RemainingTime(), onTryGetChannelComplete, this);
2318 if (result.CompletedSynchronously)
2320 return this.CompleteTryGetChannel(result);
2327 public void GetChannel(bool onUserThread)
2329 if (!this.CanGetChannel)
2331 throw Fx.AssertAndThrow("This waiter must wait for a channel thus the caller cannot attempt to get a channel.");
2334 this.isSynchronous = onUserThread;
2338 bool throwing = true;
2342 if (this.GetChannel())
2344 this.Complete(true);
2353 this.OnGetChannelFailed();
2359 bool complete = false;
2360 Exception completeException = null;
2365 complete = this.GetChannel();
2367 #pragma warning suppress 56500 // covered by FxCOP
2375 this.OnGetChannelFailed();
2376 completeException = e;
2379 if (complete || completeException != null)
2381 this.Complete(false, completeException);
2386 bool OnChannelOpened()
2388 if (this.synchronizer.OnChannelOpened(this))
2394 if (!this.IsCompleted)
2396 throw Fx.AssertAndThrow("OnChannelOpened must complete the IWaiter if it returns false.");
2403 void OnGetChannelFailed()
2405 if (this.channel != null)
2407 this.channel.Abort();
2410 this.synchronizer.OnGetChannelFailed();
2413 static void OnOpenComplete(IAsyncResult result)
2415 if (!result.CompletedSynchronously)
2417 AsyncWaiter waiter = (AsyncWaiter)result.AsyncState;
2418 bool complete = false;
2419 Exception completeException = null;
2421 waiter.isSynchronous = false;
2425 complete = waiter.CompleteOpen(result);
2427 #pragma warning suppress 56500 // covered by FxCOP
2435 completeException = e;
2440 waiter.Complete(false);
2442 else if (completeException != null)
2444 waiter.OnGetChannelFailed();
2445 waiter.Complete(false, completeException);
2450 void OnTimeoutElapsed()
2452 if (this.synchronizer.RemoveWaiter(this))
2454 this.timedOut = true;
2455 this.Complete(this.isSynchronous, null);
2459 static void OnTimeoutElapsed(object state)
2461 AsyncWaiter waiter = (AsyncWaiter)state;
2462 waiter.isSynchronous = false;
2463 waiter.OnTimeoutElapsed();
2466 static void OnTryGetChannelComplete(IAsyncResult result)
2468 if (!result.CompletedSynchronously)
2470 AsyncWaiter waiter = (AsyncWaiter)result.AsyncState;
2471 waiter.isSynchronous = false;
2472 bool complete = false;
2473 Exception completeException = null;
2477 complete = waiter.CompleteTryGetChannel(result);
2479 #pragma warning suppress 56500 // covered by FxCOP
2487 completeException = e;
2490 if (complete || completeException != null)
2492 if (completeException != null)
2493 waiter.OnGetChannelFailed();
2494 waiter.Complete(waiter.isSynchronous, completeException);
2501 if (this.synchronizer.binder.MustOpenChannel)
2503 if (this.channelParameters != null)
2505 this.channelParameters.PropagateChannelParameters(this.channel);
2508 IAsyncResult result = this.channel.BeginOpen(
2509 this.timeoutHelper.RemainingTime(), onOpenComplete, this);
2511 if (result.CompletedSynchronously)
2513 return this.CompleteOpen(result);
2520 return this.OnChannelOpened();
2524 public void Set(TChannel channel)
2527 this.channel = channel;
2528 this.Complete(false);
2531 // Always called from the user's thread.
2534 lock (this.ThisLock)
2536 if (this.timerCancelled)
2541 TimeSpan timeout = this.timeoutHelper.RemainingTime();
2543 if (timeout > TimeSpan.Zero)
2545 this.timer = new IOThreadTimer(onTimeoutElapsed, this, true);
2546 this.timer.Set(this.timeoutHelper.RemainingTime());
2551 this.OnTimeoutElapsed();
2555 sealed class SynchronizerCompletedAsyncResult : CompletedAsyncResult
2557 public SynchronizerCompletedAsyncResult(AsyncCallback callback, object state)
2558 : base(callback, state)
2564 CompletedAsyncResult.End(this);
2568 sealed class SyncWaiter : IWaiter
2572 ChannelParameterCollection channelParameters;
2573 AutoResetEvent completeEvent = new AutoResetEvent(false);
2574 Exception exception;
2575 bool getChannel = false;
2576 MaskingMode maskingMode;
2577 ChannelSynchronizer synchronizer;
2578 TimeoutHelper timeoutHelper;
2580 public SyncWaiter(ChannelSynchronizer synchronizer, bool canGetChannel,
2581 TChannel channel, TimeSpan timeout, MaskingMode maskingMode,
2582 ChannelParameterCollection channelParameters)
2586 if (channel != null)
2588 throw Fx.AssertAndThrow("This waiter must wait for a channel thus argument channel must be null.");
2592 this.synchronizer = synchronizer;
2593 this.canGetChannel = canGetChannel;
2594 this.channel = channel;
2595 this.timeoutHelper = new TimeoutHelper(timeout);
2596 this.maskingMode = maskingMode;
2597 this.channelParameters = channelParameters;
2600 public bool CanGetChannel
2604 return this.canGetChannel;
2610 this.exception = this.synchronizer.binder.GetClosedException(this.maskingMode);
2611 this.completeEvent.Set();
2616 this.exception = this.synchronizer.binder.GetFaultedException(this.maskingMode);
2617 this.completeEvent.Set();
2620 public void GetChannel(bool onUserThread)
2622 if (!this.CanGetChannel)
2624 throw Fx.AssertAndThrow("This waiter must wait for a channel thus the caller cannot attempt to get a channel.");
2627 this.getChannel = true;
2628 this.completeEvent.Set();
2631 public void Set(TChannel channel)
2633 if (channel == null)
2635 throw Fx.AssertAndThrow("Argument channel cannot be null. Caller must call Fault or Close instead.");
2638 this.channel = channel;
2639 this.completeEvent.Set();
2642 bool TryGetChannel()
2646 if (this.channel != null)
2648 channel = this.channel;
2650 else if (this.synchronizer.binder.TryGetChannel(
2651 this.timeoutHelper.RemainingTime()))
2653 if (!this.synchronizer.CompleteSetChannel(this, out channel))
2660 this.synchronizer.OnGetChannelFailed();
2664 if (this.synchronizer.binder.MustOpenChannel)
2666 bool throwing = true;
2668 if (this.channelParameters != null)
2670 this.channelParameters.PropagateChannelParameters(channel);
2675 channel.Open(this.timeoutHelper.RemainingTime());
2683 this.synchronizer.OnGetChannelFailed();
2688 if (this.synchronizer.OnChannelOpened(this))
2696 public bool TryWait(out TChannel channel)
2703 else if (this.getChannel && !this.TryGetChannel())
2709 this.completeEvent.Close();
2711 if (this.exception != null)
2713 if (this.channel != null)
2715 throw Fx.AssertAndThrow("User of IWaiter called both Set and Fault or Close.");
2718 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(this.exception);
2721 channel = this.channel;
2727 if (!TimeoutHelper.WaitOne(this.completeEvent, this.timeoutHelper.RemainingTime()))
2729 if (this.synchronizer.RemoveWaiter(this))
2735 TimeoutHelper.WaitOne(this.completeEvent, TimeSpan.MaxValue);
2744 sealed class CloseAsyncResult : AsyncResult
2746 ReliableChannelBinder<TChannel> binder;
2748 MaskingMode maskingMode;
2749 static AsyncCallback onBinderCloseComplete = Fx.ThunkCallback(new AsyncCallback(OnBinderCloseComplete));
2750 static AsyncCallback onChannelCloseComplete = Fx.ThunkCallback(new AsyncCallback(OnChannelCloseComplete));
2751 TimeoutHelper timeoutHelper;
2753 public CloseAsyncResult(ReliableChannelBinder<TChannel> binder, TChannel channel,
2754 TimeSpan timeout, MaskingMode maskingMode, AsyncCallback callback, object state)
2755 : base(callback, state)
2757 this.binder = binder;
2758 this.channel = channel;
2759 this.timeoutHelper = new TimeoutHelper(timeout);
2760 this.maskingMode = maskingMode;
2761 bool complete = false;
2765 this.binder.OnShutdown();
2766 IAsyncResult result = this.binder.OnBeginClose(timeout, onBinderCloseComplete, this);
2768 if (result.CompletedSynchronously)
2770 complete = this.CompleteBinderClose(true, result);
2780 this.binder.Abort();
2782 if (!this.binder.HandleException(e, this.maskingMode))
2794 this.Complete(true);
2798 bool CompleteBinderClose(bool synchronous, IAsyncResult result)
2800 this.binder.OnEndClose(result);
2802 if (this.channel != null)
2804 result = this.binder.BeginCloseChannel(this.channel,
2805 this.timeoutHelper.RemainingTime(), onChannelCloseComplete, this);
2807 if (result.CompletedSynchronously)
2809 return this.CompleteChannelClose(synchronous, result);
2818 this.binder.TransitionToClosed();
2823 bool CompleteChannelClose(bool synchronous, IAsyncResult result)
2825 this.binder.EndCloseChannel(this.channel, result);
2826 this.binder.TransitionToClosed();
2832 AsyncResult.End<CloseAsyncResult>(this);
2835 Exception HandleAsyncException(Exception e)
2837 this.binder.Abort();
2839 if (this.binder.HandleException(e, this.maskingMode))
2849 static void OnBinderCloseComplete(IAsyncResult result)
2851 if (!result.CompletedSynchronously)
2853 CloseAsyncResult closeResult = (CloseAsyncResult)result.AsyncState;
2855 Exception completeException;
2859 complete = closeResult.CompleteBinderClose(false, result);
2860 completeException = null;
2862 #pragma warning suppress 56500 // covered by FxCOP
2871 completeException = e;
2876 if (completeException != null)
2878 completeException = closeResult.HandleAsyncException(completeException);
2881 closeResult.Complete(false, completeException);
2886 static void OnChannelCloseComplete(IAsyncResult result)
2888 if (!result.CompletedSynchronously)
2890 CloseAsyncResult closeResult = (CloseAsyncResult)result.AsyncState;
2892 Exception completeException;
2896 complete = closeResult.CompleteChannelClose(false, result);
2897 completeException = null;
2899 #pragma warning suppress 56500 // covered by FxCOP
2908 completeException = e;
2913 if (completeException != null)
2915 completeException = closeResult.HandleAsyncException(completeException);
2918 closeResult.Complete(false, completeException);
2924 protected abstract class InputAsyncResult<TBinder> : AsyncResult
2925 where TBinder : ReliableChannelBinder<TChannel>
2931 bool isSynchronous = true;
2932 MaskingMode maskingMode;
2933 static AsyncCallback onInputComplete = Fx.ThunkCallback(new AsyncCallback(OnInputCompleteStatic));
2934 static AsyncCallback onTryGetChannelComplete = Fx.ThunkCallback(new AsyncCallback(OnTryGetChannelCompleteStatic));
2936 TimeoutHelper timeoutHelper;
2938 public InputAsyncResult(TBinder binder, bool canGetChannel, TimeSpan timeout,
2939 MaskingMode maskingMode, AsyncCallback callback, object state)
2940 : base(callback, state)
2942 this.binder = binder;
2943 this.canGetChannel = canGetChannel;
2944 this.timeoutHelper = new TimeoutHelper(timeout);
2945 this.maskingMode = maskingMode;
2948 protected abstract IAsyncResult BeginInput(TBinder binder, TChannel channel,
2949 TimeSpan timeout, AsyncCallback callback, object state);
2951 // returns true if the caller should retry
2952 bool CompleteInput(IAsyncResult result)
2958 this.success = this.EndInput(this.binder, this.channel, result, out complete);
2962 this.autoAborted = this.binder.Synchronizer.Aborting;
2963 this.binder.synchronizer.ReturnChannel();
2969 // returns true if the caller should retry
2970 bool CompleteTryGetChannel(IAsyncResult result, out bool complete)
2973 this.success = this.binder.synchronizer.EndTryGetChannel(result, out this.channel);
2975 // the synchronizer is faulted and not reestablishing or closed, or the call timed
2976 // out, complete and don't retry.
2977 if (this.channel == null)
2983 bool throwing = true;
2984 IAsyncResult inputResult = null;
2988 inputResult = this.BeginInput(this.binder, this.channel,
2989 this.timeoutHelper.RemainingTime(), onInputComplete, this);
2996 this.autoAborted = this.binder.Synchronizer.Aborting;
2997 this.binder.synchronizer.ReturnChannel();
3001 if (inputResult.CompletedSynchronously)
3003 if (this.CompleteInput(inputResult))
3023 AsyncResult.End<InputAsyncResult<TBinder>>(this);
3024 return this.success;
3027 protected abstract bool EndInput(TBinder binder, TChannel channel,
3028 IAsyncResult result, out bool complete);
3030 void OnInputComplete(IAsyncResult result)
3032 this.isSynchronous = false;
3034 Exception completeException = null;
3038 retry = this.CompleteInput(result);
3040 #pragma warning suppress 56500 // covered by FxCOP
3048 if (!this.binder.HandleException(e, this.maskingMode, this.autoAborted))
3050 completeException = e;
3061 this.StartOnNonUserThread();
3065 this.Complete(this.isSynchronous, completeException);
3069 static void OnInputCompleteStatic(IAsyncResult result)
3071 if (!result.CompletedSynchronously)
3073 InputAsyncResult<TBinder> inputResult =
3074 (InputAsyncResult<TBinder>)result.AsyncState;
3075 inputResult.OnInputComplete(result);
3079 void OnTryGetChannelComplete(IAsyncResult result)
3081 this.isSynchronous = false;
3083 bool complete = false;
3084 Exception completeException = null;
3088 retry = this.CompleteTryGetChannel(result, out complete);
3090 #pragma warning suppress 56500 // covered by FxCOP
3098 if (!this.binder.HandleException(e, this.maskingMode, this.autoAborted))
3100 completeException = e;
3109 // Can't complete AND retry.
3110 if (complete && retry)
3112 throw Fx.AssertAndThrow("The derived class' implementation of CompleteTryGetChannel() cannot indicate that the asynchronous operation should complete and retry.");
3117 this.StartOnNonUserThread();
3119 else if (complete || completeException != null)
3121 this.Complete(this.isSynchronous, completeException);
3125 static void OnTryGetChannelCompleteStatic(IAsyncResult result)
3127 if (!result.CompletedSynchronously)
3129 InputAsyncResult<TBinder> inputResult =
3130 (InputAsyncResult<TBinder>)result.AsyncState;
3131 inputResult.OnTryGetChannelComplete(result);
3135 protected bool Start()
3140 bool complete = false;
3142 this.autoAborted = false;
3146 IAsyncResult result = this.binder.synchronizer.BeginTryGetChannelForInput(
3147 canGetChannel, this.timeoutHelper.RemainingTime(),
3148 onTryGetChannelComplete, this);
3150 if (result.CompletedSynchronously)
3152 retry = this.CompleteTryGetChannel(result, out complete);
3162 if (!this.binder.HandleException(e, this.maskingMode, this.autoAborted))
3172 // Can't complete AND retry.
3173 if (complete && retry)
3175 throw Fx.AssertAndThrow("The derived class' implementation of CompleteTryGetChannel() cannot indicate that the asynchronous operation should complete and retry.");
3185 void StartOnNonUserThread()
3187 bool complete = false;
3188 Exception completeException = null;
3192 complete = this.Start();
3194 #pragma warning suppress 56500 // covered by FxCOP
3200 completeException = e;
3203 if (complete || completeException != null)
3204 this.Complete(false, completeException);
3208 sealed class MessageRequestContext : BinderRequestContext
3210 public MessageRequestContext(ReliableChannelBinder<TChannel> binder, Message message)
3211 : base(binder, message)
3215 protected override void OnAbort()
3219 protected override void OnClose(TimeSpan timeout)
3223 protected override IAsyncResult OnBeginReply(Message message, TimeSpan timeout, AsyncCallback callback, object state)
3225 return new ReplyAsyncResult(this, message, timeout, callback, state);
3228 protected override void OnEndReply(IAsyncResult result)
3230 ReplyAsyncResult.End(result);
3233 protected override void OnReply(Message message, TimeSpan timeout)
3235 if (message != null)
3237 this.Binder.Send(message, timeout, this.MaskingMode);
3241 class ReplyAsyncResult : AsyncResult
3243 static AsyncCallback onSend;
3244 MessageRequestContext context;
3246 public ReplyAsyncResult(MessageRequestContext context, Message message, TimeSpan timeout, AsyncCallback callback, object state)
3247 : base(callback, state)
3249 if (message != null)
3253 onSend = Fx.ThunkCallback(new AsyncCallback(OnSend));
3255 this.context = context;
3256 IAsyncResult result = context.Binder.BeginSend(message, timeout, context.MaskingMode, onSend, this);
3257 if (!result.CompletedSynchronously)
3261 context.Binder.EndSend(result);
3264 base.Complete(true);
3267 public static void End(IAsyncResult result)
3269 AsyncResult.End<ReplyAsyncResult>(result);
3272 static void OnSend(IAsyncResult result)
3274 if (result.CompletedSynchronously)
3279 Exception completionException = null;
3280 ReplyAsyncResult thisPtr = (ReplyAsyncResult)result.AsyncState;
3283 thisPtr.context.Binder.EndSend(result);
3285 #pragma warning suppress 56500 // covered by FxCOP
3286 catch (Exception exception)
3288 if (Fx.IsFatal(exception))
3292 completionException = exception;
3295 thisPtr.Complete(false, completionException);
3300 protected abstract class OutputAsyncResult<TBinder> : AsyncResult
3301 where TBinder : ReliableChannelBinder<TChannel>
3306 bool hasChannel = false;
3307 MaskingMode maskingMode;
3309 static AsyncCallback onTryGetChannelComplete = Fx.ThunkCallback(new AsyncCallback(OnTryGetChannelCompleteStatic));
3310 static AsyncCallback onOutputComplete = Fx.ThunkCallback(new AsyncCallback(OnOutputCompleteStatic));
3312 TimeoutHelper timeoutHelper;
3314 public OutputAsyncResult(TBinder binder, AsyncCallback callback, object state)
3315 : base(callback, state)
3317 this.binder = binder;
3320 public MaskingMode MaskingMode
3324 return this.maskingMode;
3328 protected abstract IAsyncResult BeginOutput(TBinder binder, TChannel channel,
3329 Message message, TimeSpan timeout, MaskingMode maskingMode, AsyncCallback callback,
3334 if (this.hasChannel)
3336 this.autoAborted = this.binder.Synchronizer.Aborting;
3337 this.binder.synchronizer.ReturnChannel();
3341 bool CompleteOutput(IAsyncResult result)
3343 this.EndOutput(this.binder, this.channel, this.maskingMode, result);
3348 bool CompleteTryGetChannel(IAsyncResult result)
3350 bool timedOut = !this.binder.synchronizer.EndTryGetChannel(result,
3353 if (timedOut || (this.channel == null))
3357 if (timedOut && !ReliableChannelBinderHelper.MaskHandled(maskingMode))
3359 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new TimeoutException(this.GetTimeoutString(this.timeout)));
3365 this.hasChannel = true;
3367 result = this.BeginOutput(this.binder, this.channel, this.message,
3368 this.timeoutHelper.RemainingTime(), this.maskingMode, onOutputComplete,
3371 if (result.CompletedSynchronously)
3373 return this.CompleteOutput(result);
3381 protected abstract void EndOutput(TBinder binder, TChannel channel,
3382 MaskingMode maskingMode, IAsyncResult result);
3384 protected abstract string GetTimeoutString(TimeSpan timeout);
3386 void OnOutputComplete(IAsyncResult result)
3388 if (!result.CompletedSynchronously)
3390 bool complete = false;
3391 Exception completeException = null;
3395 complete = this.CompleteOutput(result);
3397 #pragma warning suppress 56500 // covered by FxCOP
3407 if (!this.binder.HandleException(e, this.maskingMode, this.autoAborted))
3409 completeException = e;
3415 this.Complete(false, completeException);
3420 static void OnOutputCompleteStatic(IAsyncResult result)
3422 OutputAsyncResult<TBinder> outputResult =
3423 (OutputAsyncResult<TBinder>)result.AsyncState;
3425 outputResult.OnOutputComplete(result);
3428 void OnTryGetChannelComplete(IAsyncResult result)
3430 if (!result.CompletedSynchronously)
3432 bool complete = false;
3433 Exception completeException = null;
3437 complete = this.CompleteTryGetChannel(result);
3439 #pragma warning suppress 56500 // covered by FxCOP
3449 if (!this.binder.HandleException(e, this.maskingMode, this.autoAborted))
3451 completeException = e;
3457 this.Complete(false, completeException);
3462 static void OnTryGetChannelCompleteStatic(IAsyncResult result)
3464 OutputAsyncResult<TBinder> outputResult =
3465 (OutputAsyncResult<TBinder>)result.AsyncState;
3467 outputResult.OnTryGetChannelComplete(result);
3470 public void Start(Message message, TimeSpan timeout, MaskingMode maskingMode)
3472 if (!this.binder.ValidateOutputOperation(message, timeout, maskingMode))
3474 this.Complete(true);
3478 this.message = message;
3479 this.timeout = timeout;
3480 this.timeoutHelper = new TimeoutHelper(timeout);
3481 this.maskingMode = maskingMode;
3483 bool complete = false;
3487 IAsyncResult result = this.binder.synchronizer.BeginTryGetChannelForOutput(
3488 timeoutHelper.RemainingTime(), this.maskingMode, onTryGetChannelComplete, this);
3490 if (result.CompletedSynchronously)
3492 complete = this.CompleteTryGetChannel(result);
3503 if (this.binder.HandleException(e, this.maskingMode, this.autoAborted))
3515 this.Complete(true);
3520 sealed class RequestRequestContext : BinderRequestContext
3522 RequestContext innerContext;
3524 public RequestRequestContext(ReliableChannelBinder<TChannel> binder,
3525 RequestContext innerContext, Message message)
3526 : base(binder, message)
3528 if ((binder.defaultMaskingMode != MaskingMode.All) && !binder.TolerateFaults)
3530 throw Fx.AssertAndThrow("This request context is designed to catch exceptions. Thus it cannot be used if the caller expects no exception handling.");
3533 if (innerContext == null)
3535 throw Fx.AssertAndThrow("Argument innerContext cannot be null.");
3538 this.innerContext = innerContext;
3541 protected override void OnAbort()
3543 this.innerContext.Abort();
3546 protected override IAsyncResult OnBeginReply(Message message, TimeSpan timeout,
3547 AsyncCallback callback, object state)
3551 if (message != null)
3552 this.Binder.AddOutputHeaders(message);
3553 return this.innerContext.BeginReply(message, timeout, callback, state);
3555 catch (ObjectDisposedException) { }
3563 if (!this.Binder.HandleException(e, this.MaskingMode))
3568 this.innerContext.Abort();
3571 return new BinderCompletedAsyncResult(callback, state);
3574 protected override void OnClose(TimeSpan timeout)
3578 this.innerContext.Close(timeout);
3580 catch (ObjectDisposedException) { }
3588 if (!this.Binder.HandleException(e, this.MaskingMode))
3593 this.innerContext.Abort();
3597 protected override void OnEndReply(IAsyncResult result)
3599 BinderCompletedAsyncResult completedResult = result as BinderCompletedAsyncResult;
3600 if (completedResult != null)
3602 completedResult.End();
3608 this.innerContext.EndReply(result);
3610 catch (ObjectDisposedException) { }
3618 if (!this.Binder.HandleException(e, this.MaskingMode))
3623 this.innerContext.Abort();
3627 protected override void OnReply(Message message, TimeSpan timeout)
3631 if (message != null)
3632 this.Binder.AddOutputHeaders(message);
3633 this.innerContext.Reply(message, timeout);
3635 catch (ObjectDisposedException) { }
3643 if (!this.Binder.HandleException(e, this.MaskingMode))
3648 this.innerContext.Abort();
3653 sealed class SendAsyncResult : OutputAsyncResult<ReliableChannelBinder<TChannel>>
3655 public SendAsyncResult(ReliableChannelBinder<TChannel> binder, AsyncCallback callback,
3657 : base(binder, callback, state)
3661 protected override IAsyncResult BeginOutput(ReliableChannelBinder<TChannel> binder,
3662 TChannel channel, Message message, TimeSpan timeout, MaskingMode maskingMode,
3663 AsyncCallback callback, object state)
3665 binder.AddOutputHeaders(message);
3666 return binder.OnBeginSend(channel, message, timeout, callback, state);
3669 public static void End(IAsyncResult result)
3671 AsyncResult.End<SendAsyncResult>(result);
3674 protected override void EndOutput(ReliableChannelBinder<TChannel> binder,
3675 TChannel channel, MaskingMode maskingMode, IAsyncResult result)
3677 binder.OnEndSend(channel, result);
3680 protected override string GetTimeoutString(TimeSpan timeout)
3682 return SR.GetString(SR.TimeoutOnSend, timeout);
3686 sealed class TryReceiveAsyncResult : InputAsyncResult<ReliableChannelBinder<TChannel>>
3688 RequestContext requestContext;
3690 public TryReceiveAsyncResult(ReliableChannelBinder<TChannel> binder, TimeSpan timeout,
3691 MaskingMode maskingMode, AsyncCallback callback, object state)
3692 : base(binder, binder.CanGetChannelForReceive, timeout, maskingMode, callback, state)
3695 this.Complete(true);
3698 protected override IAsyncResult BeginInput(ReliableChannelBinder<TChannel> binder,
3699 TChannel channel, TimeSpan timeout, AsyncCallback callback, object state)
3701 return binder.OnBeginTryReceive(channel, timeout, callback, state);
3704 public bool End(out RequestContext requestContext)
3706 requestContext = this.requestContext;
3710 protected override bool EndInput(ReliableChannelBinder<TChannel> binder,
3711 TChannel channel, IAsyncResult result, out bool complete)
3713 bool success = binder.OnEndTryReceive(channel, result, out this.requestContext);
3715 // timed out || got message, complete immediately
3716 complete = !success || (this.requestContext != null);
3720 // the underlying channel closed or faulted
3721 binder.synchronizer.OnReadEof();
3729 static class ReliableChannelBinderHelper
3731 internal static IAsyncResult BeginCloseDuplexSessionChannel(
3732 ReliableChannelBinder<IDuplexSessionChannel> binder, IDuplexSessionChannel channel,
3733 TimeSpan timeout, AsyncCallback callback, object state)
3735 return new CloseDuplexSessionChannelAsyncResult(binder, channel, timeout, callback,
3739 internal static IAsyncResult BeginCloseReplySessionChannel(
3740 ReliableChannelBinder<IReplySessionChannel> binder, IReplySessionChannel channel,
3741 TimeSpan timeout, AsyncCallback callback, object state)
3743 return new CloseReplySessionChannelAsyncResult(binder, channel, timeout, callback,
3747 internal static void CloseDuplexSessionChannel(
3748 ReliableChannelBinder<IDuplexSessionChannel> binder, IDuplexSessionChannel channel,
3751 TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
3753 channel.Session.CloseOutputSession(timeoutHelper.RemainingTime());
3754 binder.WaitForPendingOperations(timeoutHelper.RemainingTime());
3756 TimeSpan iterationTimeout = timeoutHelper.RemainingTime();
3757 bool lastIteration = (iterationTimeout == TimeSpan.Zero);
3761 Message message = null;
3762 bool receiveThrowing = true;
3766 bool success = channel.TryReceive(iterationTimeout, out message);
3768 receiveThrowing = false;
3769 if (success && message == null)
3771 channel.Close(timeoutHelper.RemainingTime());
3780 if (receiveThrowing)
3782 if (!MaskHandled(binder.DefaultMaskingMode) || !binder.IsHandleable(e))
3785 receiveThrowing = false;
3794 if (message != null)
3797 if (receiveThrowing)
3801 if (lastIteration || channel.State != CommunicationState.Opened)
3804 iterationTimeout = timeoutHelper.RemainingTime();
3805 lastIteration = (iterationTimeout == TimeSpan.Zero);
3811 internal static void CloseReplySessionChannel(
3812 ReliableChannelBinder<IReplySessionChannel> binder, IReplySessionChannel channel,
3815 TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
3817 binder.WaitForPendingOperations(timeoutHelper.RemainingTime());
3819 TimeSpan iterationTimeout = timeoutHelper.RemainingTime();
3820 bool lastIteration = (iterationTimeout == TimeSpan.Zero);
3824 RequestContext context = null;
3825 bool receiveThrowing = true;
3829 bool success = channel.TryReceiveRequest(iterationTimeout, out context);
3831 receiveThrowing = false;
3832 if (success && context == null)
3834 channel.Close(timeoutHelper.RemainingTime());
3843 if (receiveThrowing)
3845 if (!MaskHandled(binder.DefaultMaskingMode) || !binder.IsHandleable(e))
3848 receiveThrowing = false;
3857 if (context != null)
3859 context.RequestMessage.Close();
3863 if (receiveThrowing)
3867 if (lastIteration || channel.State != CommunicationState.Opened)
3870 iterationTimeout = timeoutHelper.RemainingTime();
3871 lastIteration = (iterationTimeout == TimeSpan.Zero);
3877 internal static void EndCloseDuplexSessionChannel(IDuplexSessionChannel channel,
3878 IAsyncResult result)
3880 CloseDuplexSessionChannelAsyncResult.End(result);
3883 internal static void EndCloseReplySessionChannel(IReplySessionChannel channel,
3884 IAsyncResult result)
3886 CloseReplySessionChannelAsyncResult.End(result);
3889 internal static bool MaskHandled(MaskingMode maskingMode)
3891 return (maskingMode & MaskingMode.Handled) == MaskingMode.Handled;
3894 internal static bool MaskUnhandled(MaskingMode maskingMode)
3896 return (maskingMode & MaskingMode.Unhandled) == MaskingMode.Unhandled;
3899 abstract class CloseInputSessionChannelAsyncResult<TChannel, TItem> : AsyncResult
3900 where TChannel : class, IChannel
3903 static AsyncCallback onChannelCloseCompleteStatic =
3905 new AsyncCallback(OnChannelCloseCompleteStatic));
3906 static AsyncCallback onInputCompleteStatic =
3907 Fx.ThunkCallback(new AsyncCallback(OnInputCompleteStatic));
3908 static AsyncCallback onWaitForPendingOperationsCompleteStatic =
3910 new AsyncCallback(OnWaitForPendingOperationsCompleteStatic));
3911 ReliableChannelBinder<TChannel> binder;
3914 TimeoutHelper timeoutHelper;
3916 protected CloseInputSessionChannelAsyncResult(
3917 ReliableChannelBinder<TChannel> binder, TChannel channel,
3918 TimeSpan timeout, AsyncCallback callback, object state)
3919 : base(callback, state)
3921 this.binder = binder;
3922 this.channel = channel;
3923 this.timeoutHelper = new TimeoutHelper(timeout);
3926 protected TChannel Channel
3930 return this.channel;
3934 protected TimeSpan RemainingTime
3938 return this.timeoutHelper.RemainingTime();
3942 protected bool Begin()
3944 bool complete = false;
3945 IAsyncResult result = this.binder.BeginWaitForPendingOperations(
3946 this.RemainingTime, onWaitForPendingOperationsCompleteStatic,
3949 if (result.CompletedSynchronously)
3950 complete = this.HandleWaitForPendingOperationsComplete(result);
3955 protected abstract IAsyncResult BeginTryInput(TimeSpan timeout, AsyncCallback callback,
3958 protected abstract void DisposeItem(TItem item);
3960 protected abstract bool EndTryInput(IAsyncResult result, out TItem item);
3962 void HandleChannelCloseComplete(IAsyncResult result)
3964 this.channel.EndClose(result);
3967 bool HandleInputComplete(IAsyncResult result, out bool gotEof)
3970 bool endThrowing = true;
3976 bool success = false;
3978 success = this.EndTryInput(result, out item);
3979 endThrowing = false;
3981 if (!success || item != null)
3983 if (this.lastReceive || this.channel.State != CommunicationState.Opened)
3985 this.channel.Abort();
3996 result = this.channel.BeginClose(this.RemainingTime,
3997 onChannelCloseCompleteStatic, this);
3998 if (result.CompletedSynchronously)
4000 this.HandleChannelCloseComplete(result);
4015 if (!MaskHandled(binder.DefaultMaskingMode) || !binder.IsHandleable(e))
4018 if (this.lastReceive || this.channel.State != CommunicationState.Opened)
4020 this.channel.Abort();
4034 this.DisposeItem(item);
4037 this.channel.Abort();
4041 bool HandleWaitForPendingOperationsComplete(IAsyncResult result)
4043 this.binder.EndWaitForPendingOperations(result);
4044 return this.WaitForEof();
4047 static void OnChannelCloseCompleteStatic(IAsyncResult result)
4049 if (result.CompletedSynchronously)
4052 CloseInputSessionChannelAsyncResult<TChannel, TItem> closeResult =
4053 (CloseInputSessionChannelAsyncResult<TChannel, TItem>)result.AsyncState;
4055 Exception completeException = null;
4059 closeResult.HandleChannelCloseComplete(result);
4066 completeException = e;
4069 closeResult.Complete(false, completeException);
4072 static void OnInputCompleteStatic(IAsyncResult result)
4074 if (result.CompletedSynchronously)
4077 CloseInputSessionChannelAsyncResult<TChannel, TItem> closeResult =
4078 (CloseInputSessionChannelAsyncResult<TChannel, TItem>)result.AsyncState;
4080 bool complete = false;
4081 Exception completeException = null;
4087 complete = closeResult.HandleInputComplete(result, out gotEof);
4088 if (!complete && !gotEof)
4089 complete = closeResult.WaitForEof();
4096 completeException = e;
4099 if (complete || completeException != null)
4100 closeResult.Complete(false, completeException);
4103 static void OnWaitForPendingOperationsCompleteStatic(IAsyncResult result)
4105 if (result.CompletedSynchronously)
4108 CloseInputSessionChannelAsyncResult<TChannel, TItem> closeResult =
4109 (CloseInputSessionChannelAsyncResult<TChannel, TItem>)result.AsyncState;
4111 bool complete = false;
4112 Exception completeException = null;
4116 complete = closeResult.HandleWaitForPendingOperationsComplete(result);
4123 completeException = e;
4126 if (complete || completeException != null)
4127 closeResult.Complete(false, completeException);
4132 TimeSpan iterationTimeout = this.RemainingTime;
4133 this.lastReceive = (iterationTimeout == TimeSpan.Zero);
4137 IAsyncResult result = null;
4141 result = this.BeginTryInput(iterationTimeout, onInputCompleteStatic, this);
4148 if (!MaskHandled(this.binder.DefaultMaskingMode) || !this.binder.IsHandleable(e))
4154 if (result.CompletedSynchronously)
4157 bool complete = this.HandleInputComplete(result, out gotEof);
4159 if (complete || gotEof)
4166 if (this.lastReceive || this.channel.State != CommunicationState.Opened)
4168 this.channel.Abort();
4172 iterationTimeout = this.RemainingTime;
4173 this.lastReceive = (iterationTimeout == TimeSpan.Zero);
4180 sealed class CloseDuplexSessionChannelAsyncResult :
4181 CloseInputSessionChannelAsyncResult<IDuplexSessionChannel, Message>
4183 static AsyncCallback onCloseOutputSessionCompleteStatic =
4185 new AsyncCallback(OnCloseOutputSessionCompleteStatic));
4187 public CloseDuplexSessionChannelAsyncResult(
4188 ReliableChannelBinder<IDuplexSessionChannel> binder, IDuplexSessionChannel channel,
4189 TimeSpan timeout, AsyncCallback callback, object state)
4190 : base(binder, channel, timeout, callback, state)
4192 bool complete = false;
4194 IAsyncResult result = this.Channel.Session.BeginCloseOutputSession(
4195 this.RemainingTime, onCloseOutputSessionCompleteStatic, this);
4197 if (result.CompletedSynchronously)
4198 complete = this.HandleCloseOutputSessionComplete(result);
4201 this.Complete(true);
4204 protected override IAsyncResult BeginTryInput(TimeSpan timeout, AsyncCallback callback, object state)
4206 return this.Channel.BeginTryReceive(timeout, callback, state);
4209 protected override void DisposeItem(Message item)
4214 public static void End(IAsyncResult result)
4216 AsyncResult.End<CloseDuplexSessionChannelAsyncResult>(result);
4219 protected override bool EndTryInput(IAsyncResult result, out Message item)
4221 return this.Channel.EndTryReceive(result, out item);
4224 bool HandleCloseOutputSessionComplete(IAsyncResult result)
4226 this.Channel.Session.EndCloseOutputSession(result);
4227 return this.Begin();
4230 static void OnCloseOutputSessionCompleteStatic(IAsyncResult result)
4232 if (result.CompletedSynchronously)
4235 CloseDuplexSessionChannelAsyncResult closeResult =
4236 (CloseDuplexSessionChannelAsyncResult)result.AsyncState;
4238 bool complete = false;
4239 Exception completeException = null;
4243 complete = closeResult.HandleCloseOutputSessionComplete(result);
4250 completeException = e;
4253 if (complete || completeException != null)
4254 closeResult.Complete(false, completeException);
4258 sealed class CloseReplySessionChannelAsyncResult :
4259 CloseInputSessionChannelAsyncResult<IReplySessionChannel, RequestContext>
4261 public CloseReplySessionChannelAsyncResult(
4262 ReliableChannelBinder<IReplySessionChannel> binder, IReplySessionChannel channel,
4263 TimeSpan timeout, AsyncCallback callback, object state)
4264 : base(binder, channel, timeout, callback, state)
4267 this.Complete(true);
4270 protected override IAsyncResult BeginTryInput(TimeSpan timeout, AsyncCallback callback, object state)
4272 return this.Channel.BeginTryReceiveRequest(timeout, callback, state);
4275 protected override void DisposeItem(RequestContext item)
4277 item.RequestMessage.Close();
4281 public static void End(IAsyncResult result)
4283 AsyncResult.End<CloseReplySessionChannelAsyncResult>(result);
4286 protected override bool EndTryInput(IAsyncResult result, out RequestContext item)
4288 return this.Channel.EndTryReceiveRequest(result, out item);