ReliableChannelBinder.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ WCF / WCF / 3.5.30729.1 / untmp / Orcas / SP / ndp / cdf / src / WCF / ServiceModel / System / ServiceModel / Channels / ReliableChannelBinder.cs / 1 / ReliableChannelBinder.cs

                            //------------------------------------------------------------ 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------

namespace System.ServiceModel.Channels 
{
    using System.Collections.Generic; 
    using System.ServiceModel; 
    using System.ServiceModel.Security;
    using System.Threading; 

    enum TolerateFaultsMode
    {
        Never, 
        IfNotSecuritySession,
        Always 
    } 

    [Flags] 
    enum MaskingMode
    {
        None = 0x0,
        Handled = 0x1, 
        Unhandled = 0x2,
        All = Handled | Unhandled 
    } 

    abstract class ReliableChannelBinder : IReliableChannelBinder 
        where TChannel : class, IChannel
    {
        bool aborted = false;
        TimeSpan defaultCloseTimeout; 
        MaskingMode defaultMaskingMode;
        TimeSpan defaultSendTimeout; 
        AsyncCallback onCloseChannelComplete; 
        CommunicationState state = CommunicationState.Created;
        ChannelSynchronizer synchronizer; 
        object thisLock = new object();

        protected ReliableChannelBinder(TChannel channel, MaskingMode maskingMode,
            TolerateFaultsMode faultMode, TimeSpan defaultCloseTimeout, 
            TimeSpan defaultSendTimeout)
        { 
            if ((maskingMode != MaskingMode.None) && (maskingMode != MaskingMode.All)) 
            {
                DiagnosticUtility.DebugAssert("ReliableChannelBinder was implemented with only 2 default masking modes, None and All."); 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false);
            }

            this.defaultMaskingMode = maskingMode; 
            this.defaultCloseTimeout = defaultCloseTimeout;
            this.defaultSendTimeout = defaultSendTimeout; 
 
            this.synchronizer = new ChannelSynchronizer(this, channel, faultMode);
        } 

        protected abstract bool CanGetChannelForReceive
        {
            get; 
        }
 
        public abstract bool CanSendAsynchronously 
        {
            get; 
        }

        public virtual ChannelParameterCollection ChannelParameters
        { 
            get { return null; }
        } 
 
        public IChannel Channel
        { 
            get
            {
                return this.synchronizer.CurrentChannel;
            } 
        }
 
        public bool Connected 
        {
            get 
            {
                return this.synchronizer.Connected;
            }
        } 

        public MaskingMode DefaultMaskingMode 
        { 
            get
            { 
                return this.defaultMaskingMode;
            }
        }
 
        public TimeSpan DefaultSendTimeout
        { 
            get 
            {
                return this.defaultSendTimeout; 
            }
        }

        public abstract bool HasSession 
        {
            get; 
        } 

        public abstract EndpointAddress LocalAddress 
        {
            get;
        }
 
        protected abstract bool MustCloseChannel
        { 
            get; 
        }
 
        protected abstract bool MustOpenChannel
        {
            get;
        } 

        public abstract EndpointAddress RemoteAddress 
        { 
            get;
        } 

        public CommunicationState State
        {
            get 
            {
                return this.state; 
            } 
        }
 
        protected ChannelSynchronizer Synchronizer
        {
            get
            { 
                return this.synchronizer;
            } 
        } 

        protected object ThisLock 
        {
            get
            {
                return this.thisLock; 
            }
        } 
 
        bool TolerateFaults
        { 
            get
            {
                return this.synchronizer.TolerateFaults;
            } 
        }
 
        public event EventHandler ConnectionLost; 
        public event BinderExceptionHandler Faulted;
        public event BinderExceptionHandler OnException; 


        public void Abort()
        { 
            TChannel channel;
            lock (this.ThisLock) 
            { 
                this.aborted = true;
 
                if (this.state == CommunicationState.Closed)
                {
                    return;
                } 

                this.state = CommunicationState.Closing; 
                channel = this.synchronizer.StopSynchronizing(true); 

                if (!this.MustCloseChannel) 
                {
                    channel = null;
                }
            } 

            this.synchronizer.UnblockWaiters(); 
            this.OnShutdown(); 
            this.OnAbort();
 
            if (channel != null)
            {
                channel.Abort();
            } 

            this.TransitionToClosed(); 
        } 

        protected virtual void AddOutputHeaders(Message message) 
        {
        }

        public IAsyncResult BeginClose(TimeSpan timeout, AsyncCallback callback, 
            object state)
        { 
            return this.BeginClose(timeout, this.defaultMaskingMode, callback, state); 
        }
 
        public IAsyncResult BeginClose(TimeSpan timeout, MaskingMode maskingMode,
            AsyncCallback callback, object state)
        {
            this.ThrowIfTimeoutNegative(timeout); 
            TChannel channel;
 
            if (this.CloseCore(out channel)) 
            {
                return new CompletedAsyncResult(callback, state); 
            }
            else
            {
                return new CloseAsyncResult(this, channel, timeout, maskingMode, callback, state); 
            }
        } 
 
        protected virtual IAsyncResult BeginCloseChannel(TChannel channel, TimeSpan timeout,
            AsyncCallback callback, object state) 
        {
            return channel.BeginClose(timeout, callback, state);
        }
 
        public IAsyncResult BeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
        { 
            this.ThrowIfTimeoutNegative(timeout); 

            if (this.OnOpening(this.defaultMaskingMode)) 
            {
                try
                {
                    return this.OnBeginOpen(timeout, callback, state); 
                }
                catch (Exception e) 
                { 
                    if (DiagnosticUtility.IsFatal(e))
                    { 
                        throw;
                    }

                    this.Fault(null); 

                    if (this.defaultMaskingMode == MaskingMode.None) 
                    { 
                        throw;
                    } 
                    else
                    {
                        this.RaiseOnException(e);
                    } 
                }
            } 
 
            return new BinderCompletedAsyncResult(callback, state);
        } 

        public IAsyncResult BeginSend(Message message, TimeSpan timeout, AsyncCallback callback,
            object state)
        { 
            return this.BeginSend(message, timeout, this.defaultMaskingMode, callback, state);
        } 
 
        public IAsyncResult BeginSend(Message message, TimeSpan timeout, MaskingMode maskingMode,
            AsyncCallback callback, object state) 
        {
            SendAsyncResult result = new SendAsyncResult(this, callback, state);
            result.Start(message, timeout, maskingMode);
            return result; 
        }
 
        // ChannelSynchronizer helper, cannot take a lock. 
        protected abstract IAsyncResult BeginTryGetChannel(TimeSpan timeout,
            AsyncCallback callback, object state); 

        public virtual IAsyncResult BeginTryReceive(TimeSpan timeout, AsyncCallback callback,
            object state)
        { 
            return this.BeginTryReceive(timeout, this.defaultMaskingMode, callback, state);
        } 
 
        public virtual IAsyncResult BeginTryReceive(TimeSpan timeout, MaskingMode maskingMode,
            AsyncCallback callback, object state) 
        {
            if (this.ValidateInputOperation(timeout))
                return new TryReceiveAsyncResult(this, timeout, maskingMode, callback, state);
            else 
                return new CompletedAsyncResult(callback, state);
        } 
 
        internal IAsyncResult BeginWaitForPendingOperations(TimeSpan timeout,
            AsyncCallback callback, object state) 
        {
            return this.synchronizer.BeginWaitForPendingOperations(timeout, callback, state);
        }
 
        bool CloseCore(out TChannel channel)
        { 
            channel = null; 
            bool abort = true;
            bool abortChannel = false; 

            lock (this.ThisLock)
            {
                if ((this.state == CommunicationState.Closing) 
                    || (this.state == CommunicationState.Closed))
                { 
                    return true; 
                }
 
                if (this.state == CommunicationState.Opened)
                {
                    this.state = CommunicationState.Closing;
                    channel = this.synchronizer.StopSynchronizing(true); 
                    abort = false;
 
                    if (!this.MustCloseChannel) 
                    {
                        channel = null; 
                    }

                    if (channel != null)
                    { 
                        CommunicationState channelState = channel.State;
 
                        if ((channelState == CommunicationState.Created) 
                            || (channelState == CommunicationState.Opening)
                            || (channelState == CommunicationState.Faulted)) 
                        {
                            abortChannel = true;
                        }
                        else if ((channelState == CommunicationState.Closing) 
                            || (channelState == CommunicationState.Closed))
                        { 
                            channel = null; 
                        }
                    } 
                }
            }

            this.synchronizer.UnblockWaiters(); 

            if (abort) 
            { 
                this.Abort();
                return true; 
            }
            else
            {
                if (abortChannel) 
                {
                    channel.Abort(); 
                    channel = null; 
                }
 
                return false;
            }
        }
 
        public void Close(TimeSpan timeout)
        { 
            this.Close(timeout, this.defaultMaskingMode); 
        }
 
        public void Close(TimeSpan timeout, MaskingMode maskingMode)
        {
            this.ThrowIfTimeoutNegative(timeout);
            TimeoutHelper timeoutHelper = new TimeoutHelper(timeout); 
            TChannel channel;
 
            if (this.CloseCore(out channel)) 
            {
                return; 
            }

            try
            { 
                this.OnShutdown();
                this.OnClose(timeoutHelper.RemainingTime()); 
 
                if (channel != null)
                { 
                    this.CloseChannel(channel, timeoutHelper.RemainingTime());
                }

                this.TransitionToClosed(); 
            }
            catch (Exception e) 
            { 
                if (DiagnosticUtility.IsFatal(e))
                { 
                    throw;
                }

                this.Abort(); 

                if (!this.HandleException(e, maskingMode)) 
                { 
                    throw;
                } 
            }
        }

        // The ChannelSynchronizer calls this from an operation thread so this method must not 
        // block.
        void CloseChannel(TChannel channel) 
        { 
            if (!this.MustCloseChannel)
            { 
                DiagnosticUtility.DebugAssert("MustCloseChannel is false when there is no receive loop and this method is called when there is a receive loop.");
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false);
            }
 
            if (this.onCloseChannelComplete == null)
            { 
                this.onCloseChannelComplete = DiagnosticUtility.ThunkAsyncCallback(new AsyncCallback(this.OnCloseChannelComplete)); 
            }
 
            try
            {
                IAsyncResult result = channel.BeginClose(onCloseChannelComplete, channel);
 
                if (result.CompletedSynchronously)
                { 
                    channel.EndClose(result); 
                }
            } 
#pragma warning suppress 56500 // covered by FxCOP
            catch (Exception e)
            {
                if (DiagnosticUtility.IsFatal(e)) 
                {
                    throw; 
                } 

                this.HandleException(e, MaskingMode.All); 
            }
        }

        protected virtual void CloseChannel(TChannel channel, TimeSpan timeout) 
        {
            channel.Close(timeout); 
        } 

        public void EndClose(IAsyncResult result) 
        {
            CloseAsyncResult closeResult = result as CloseAsyncResult;

            if (closeResult != null) 
            {
                closeResult.End(); 
            } 
            else
            { 
                CompletedAsyncResult.End(result);
            }
        }
 
        protected virtual void EndCloseChannel(TChannel channel, IAsyncResult result)
        { 
            channel.EndClose(result); 
        }
 
        public void EndOpen(IAsyncResult result)
        {
            BinderCompletedAsyncResult completedResult = result as BinderCompletedAsyncResult;
 
            if (completedResult != null)
            { 
                completedResult.End(); 
            }
            else 
            {
                try
                {
                    this.OnEndOpen(result); 
                }
                catch (Exception e) 
                { 
                    if (DiagnosticUtility.IsFatal(e))
                    { 
                        throw;
                    }

                    this.Fault(null); 

                    if (this.defaultMaskingMode == MaskingMode.None) 
                    { 
                        throw;
                    } 
                    else
                    {
                        this.RaiseOnException(e);
                        return; 
                    }
                } 
 
                this.synchronizer.StartSynchronizing();
                this.OnOpened(); 
            }
        }

        public void EndSend(IAsyncResult result) 
        {
            SendAsyncResult.End(result); 
        } 

        // ChannelSynchronizer helper, cannot take a lock. 
        protected abstract bool EndTryGetChannel(IAsyncResult result);

        public virtual bool EndTryReceive(IAsyncResult result, out RequestContext requestContext)
        { 
            TryReceiveAsyncResult tryReceiveResult = result as TryReceiveAsyncResult;
 
            if (tryReceiveResult != null) 
            {
                return tryReceiveResult.End(out requestContext); 
            }
            else
            {
                CompletedAsyncResult.End(result); 
                requestContext = null;
                return true; 
            } 
        }
 
        public void EndWaitForPendingOperations(IAsyncResult result)
        {
            this.synchronizer.EndWaitForPendingOperations(result);
        } 

        protected void Fault(Exception e) 
        { 
            lock (this.ThisLock)
            { 
                if (this.state == CommunicationState.Created)
                {
                    DiagnosticUtility.DebugAssert("The binder should not detect the inner channel's faults until after the binder is opened.");
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); 
                }
 
                if ((this.state == CommunicationState.Faulted) 
                    || (this.state == CommunicationState.Closed))
                { 
                    return;
                }

                this.state = CommunicationState.Faulted; 
                this.synchronizer.StopSynchronizing(false);
            } 
 
            this.synchronizer.UnblockWaiters();
 
            BinderExceptionHandler handler = this.Faulted;

            if (handler != null)
            { 
                handler(this, e);
            } 
        } 

        // ChannelSynchronizer helper, cannot take a lock. 
        Exception GetClosedException(MaskingMode maskingMode)
        {
            if (ReliableChannelBinderHelper.MaskHandled(maskingMode))
            { 
                return null;
            } 
            else if (this.aborted) 
            {
                return new CommunicationObjectAbortedException(SR.GetString( 
                    SR.CommunicationObjectAborted1, this.GetType().ToString()));
            }
            else
            { 
                return new ObjectDisposedException(this.GetType().ToString());
            } 
        } 

        // Must be called within lock (this.ThisLock) 
        Exception GetClosedOrFaultedException(MaskingMode maskingMode)
        {
            if (this.state == CommunicationState.Faulted)
            { 
                return this.GetFaultedException(maskingMode);
            } 
            else if ((this.state == CommunicationState.Closing) 
               || (this.state == CommunicationState.Closed))
            { 
                return this.GetClosedException(maskingMode);
            }
            else
            { 
                DiagnosticUtility.DebugAssert("Caller is attempting to get a terminal exception in a non-terminal state.");
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); 
            } 
        }
 
        // ChannelSynchronizer helper, cannot take a lock.
        Exception GetFaultedException(MaskingMode maskingMode)
        {
            if (ReliableChannelBinderHelper.MaskHandled(maskingMode)) 
            {
                return null; 
            } 
            else
            { 
                return new CommunicationObjectFaultedException(SR.GetString(
                    SR.CommunicationObjectFaulted1, this.GetType().ToString()));
            }
        } 

        public abstract ISession GetInnerSession(); 
 
        public void HandleException(Exception e)
        { 
            this.HandleException(e, MaskingMode.All);
        }

        protected bool HandleException(Exception e, MaskingMode maskingMode) 
        {
            if (this.TolerateFaults && (e is CommunicationObjectFaultedException)) 
            { 
                return true;
            } 

            if (this.IsHandleable(e))
            {
                return ReliableChannelBinderHelper.MaskHandled(maskingMode); 
            }
 
            bool maskUnhandled = ReliableChannelBinderHelper.MaskUnhandled(maskingMode); 

            if (maskUnhandled) 
            {
                this.RaiseOnException(e);
            }
 
            return maskUnhandled;
        } 
 
        protected bool HandleException(Exception e, MaskingMode maskingMode, bool autoAborted)
        { 
            if (this.TolerateFaults && autoAborted && e is CommunicationObjectAbortedException)
            {
                return true;
            } 

            return this.HandleException(e, maskingMode); 
        } 

        // ChannelSynchronizer helper, cannot take a lock. 
        protected abstract bool HasSecuritySession(TChannel channel);

        public bool IsHandleable(Exception e)
        { 
            if (e is ProtocolException)
            { 
                return false; 
            }
 
            return (e is CommunicationException)
                || (e is TimeoutException);
        }
 
        protected abstract void OnAbort();
        protected abstract IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback callback, 
            object state); 
        protected abstract IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback,
            object state); 

        protected virtual IAsyncResult OnBeginSend(TChannel channel, Message message,
            TimeSpan timeout, AsyncCallback callback, object state)
        { 
            DiagnosticUtility.DebugAssert("The derived class does not support the BeginSend operation.");
            throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); 
        } 

        protected virtual IAsyncResult OnBeginTryReceive(TChannel channel, TimeSpan timeout, 
            AsyncCallback callback, object state)
        {
            DiagnosticUtility.DebugAssert("The derived class does not support the BeginTryReceive operation.");
            throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); 
        }
 
        protected abstract void OnClose(TimeSpan timeout); 

        void OnCloseChannelComplete(IAsyncResult result) 
        {
            if (result.CompletedSynchronously)
            {
                return; 
            }
 
            TChannel channel = (TChannel)result.AsyncState; 

            try 
            {
                channel.EndClose(result);
            }
#pragma warning suppress 56500 // covered by FxCOP 
            catch (Exception e)
            { 
                if (DiagnosticUtility.IsFatal(e)) 
                {
                    throw; 
                }

                this.HandleException(e, MaskingMode.All);
            } 
        }
 
        protected abstract void OnEndClose(IAsyncResult result); 
        protected abstract void OnEndOpen(IAsyncResult result);
 
        protected virtual void OnEndSend(TChannel channel, IAsyncResult result)
        {
            DiagnosticUtility.DebugAssert("The derived class does not support the EndSend operation.");
            throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); 
        }
 
        protected virtual bool OnEndTryReceive(TChannel channel, IAsyncResult result, 
            out RequestContext requestContext)
        { 
            DiagnosticUtility.DebugAssert("The derived class does not support the EndTryReceive operation.");
            throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false);
        }
 
        void OnInnerChannelFaulted()
        { 
            if (!this.TolerateFaults) 
                return;
 
            EventHandler handler = this.ConnectionLost;

            if (handler != null)
                handler(this, EventArgs.Empty); 
        }
 
        protected abstract void OnOpen(TimeSpan timeout); 

        void OnOpened() 
        {
            lock (this.ThisLock)
            {
                if (this.state == CommunicationState.Opening) 
                {
                    this.state = CommunicationState.Opened; 
                } 
            }
        } 

        bool OnOpening(MaskingMode maskingMode)
        {
            lock (this.ThisLock) 
            {
                if (this.state != CommunicationState.Created) 
                { 
                    Exception e = null;
 
                    if ((this.state == CommunicationState.Opening)
                        || (this.state == CommunicationState.Opened))
                    {
                        if (!ReliableChannelBinderHelper.MaskUnhandled(maskingMode)) 
                        {
                            e = new InvalidOperationException(SR.GetString( 
                                SR.CommunicationObjectCannotBeModifiedInState, 
                                this.GetType().ToString(), this.state.ToString()));
                        } 
                    }
                    else
                    {
                        e = this.GetClosedOrFaultedException(maskingMode); 
                    }
 
                    if (e != null) 
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(e); 
                    }

                    return false;
                } 
                else
                { 
                    this.state = CommunicationState.Opening; 
                    return true;
                } 
            }
        }

        protected virtual void OnShutdown() 
        {
        } 
 
        protected virtual void OnSend(TChannel channel, Message message, TimeSpan timeout)
        { 
            DiagnosticUtility.DebugAssert("The derived class does not support the Send operation.");
            throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false);
        }
 
        protected virtual bool OnTryReceive(TChannel channel, TimeSpan timeout,
            out RequestContext requestContext) 
        { 
            DiagnosticUtility.DebugAssert("The derived class does not support the TryReceive operation.");
            throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); 
        }

        public void Open(TimeSpan timeout)
        { 
            this.ThrowIfTimeoutNegative(timeout);
 
            if (!this.OnOpening(this.defaultMaskingMode)) 
            {
                return; 
            }

            try
            { 
                this.OnOpen(timeout);
            } 
            catch (Exception e) 
            {
                if (DiagnosticUtility.IsFatal(e)) 
                {
                    throw;
                }
 
                this.Fault(null);
 
                if (this.defaultMaskingMode == MaskingMode.None) 
                {
                    throw; 
                }
                else
                {
                    this.RaiseOnException(e); 
                    return;
                } 
            } 

            this.synchronizer.StartSynchronizing(); 
            this.OnOpened();
        }

        void RaiseOnException(Exception e) 
        {
            BinderExceptionHandler handler = this.OnException;; 
 
            if (handler != null)
            { 
                handler(this, e);
            }
        }
 
        public void Send(Message message, TimeSpan timeout)
        { 
            this.Send(message, timeout, this.defaultMaskingMode); 
        }
 
        public void Send(Message message, TimeSpan timeout, MaskingMode maskingMode)
        {
            if (!this.ValidateOutputOperation(message, timeout, maskingMode))
            { 
                return;
            } 
 
            bool autoAborted = false;
 
            try
            {
                TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
                TChannel channel; 

                if (!this.synchronizer.TryGetChannelForOutput(timeoutHelper.RemainingTime(), maskingMode, 
                    out channel)) 
                {
                    if (!ReliableChannelBinderHelper.MaskHandled(maskingMode)) 
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                            new TimeoutException(SR.GetString(SR.TimeoutOnSend, timeout)));
                    } 

                    return; 
                } 

                if (channel == null) 
                {
                    return;
                }
 
                this.AddOutputHeaders(message);
 
                try 
                {
                    this.OnSend(channel, message, timeoutHelper.RemainingTime()); 
                }
                finally
                {
                    autoAborted = this.Synchronizer.Aborting; 
                    this.synchronizer.ReturnChannel();
                } 
            } 
            catch (Exception e)
            { 
                if (DiagnosticUtility.IsFatal(e))
                {
                    throw;
                } 

                if (!this.HandleException(e, maskingMode, autoAborted)) 
                { 
                    throw;
                } 
            }
        }

        public void SetMaskingMode(RequestContext context, MaskingMode maskingMode) 
        {
            BinderRequestContext binderContext = (BinderRequestContext)context; 
            binderContext.SetMaskingMode(maskingMode); 
        }
 
        // throwDisposed indicates whether to throw in the Faulted, Closing, and Closed states.
        // returns true if in Opened state
        bool ThrowIfNotOpenedAndNotMasking(MaskingMode maskingMode, bool throwDisposed)
        { 
            lock (this.ThisLock)
            { 
                if (this.State == CommunicationState.Created) 
                {
                    DiagnosticUtility.DebugAssert("Messaging operations cannot be called when the binder is in the Created state."); 
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false);
                }

                if (this.State == CommunicationState.Opening) 
                {
                    DiagnosticUtility.DebugAssert("Messaging operations cannot be called when the binder is in the Opening state."); 
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); 
                }
 
                if (this.State == CommunicationState.Opened)
                {
                    return true;
                } 

                // state is Faulted, Closing, or Closed 
                if (throwDisposed) 
                {
                    Exception e = this.GetClosedOrFaultedException(maskingMode); 

                    if (e != null)
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(e); 
                    }
                } 
 
                return false;
            } 
        }

        void ThrowIfTimeoutNegative(TimeSpan timeout)
        { 
            if (timeout < TimeSpan.Zero)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( 
                    new ArgumentOutOfRangeException("timeout", timeout, SR.SFxTimeoutOutOfRange0));
            } 
        }

        void TransitionToClosed()
        { 
            lock (this.ThisLock)
            { 
                if ((this.state != CommunicationState.Closing) 
                    && (this.state != CommunicationState.Closed)
                    && (this.state != CommunicationState.Faulted)) 
                {
                    DiagnosticUtility.DebugAssert("Caller cannot transition to the Closed state from a non-terminal state.");
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false);
                } 

                this.state = CommunicationState.Closed; 
            } 
        }
 
        // ChannelSynchronizer helper, cannot take a lock.
        protected abstract bool TryGetChannel(TimeSpan timeout);

        public virtual bool TryReceive(TimeSpan timeout, out RequestContext requestContext) 
        {
            return this.TryReceive(timeout, out requestContext, this.defaultMaskingMode); 
        } 

        public virtual bool TryReceive(TimeSpan timeout, out RequestContext requestContext, MaskingMode maskingMode) 
        {
            if (maskingMode != MaskingMode.None)
            {
                DiagnosticUtility.DebugAssert("This method was implemented only for the case where we do not mask exceptions."); 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false);
            } 
 
            if (!this.ValidateInputOperation(timeout))
            { 
                requestContext = null;
                return true;
            }
 
            TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
 
            while (true) 
            {
                bool autoAborted = false; 

                try
                {
                    TChannel channel; 
                    bool success = !this.synchronizer.TryGetChannelForInput(
                        this.CanGetChannelForReceive, timeoutHelper.RemainingTime(), out channel); 
 
                    if (channel == null)
                    { 
                        requestContext = null;
                        return success;
                    }
 
                    try
                    { 
                        success = this.OnTryReceive(channel, timeoutHelper.RemainingTime(), 
                            out requestContext);
 
                        // timed out || got message, return immediately
                        if (!success || (requestContext != null))
                        {
                            return success; 
                        }
 
                        // the underlying channel closed or faulted, retry 
                        this.synchronizer.OnReadEof();
                    } 
                    finally
                    {
                        autoAborted = this.Synchronizer.Aborting;
                        this.synchronizer.ReturnChannel(); 
                    }
                } 
                catch (Exception e) 
                {
                    if (DiagnosticUtility.IsFatal(e)) 
                    {
                        throw;
                    }
 
                    if (!this.HandleException(e, maskingMode, autoAborted))
                    { 
                        throw; 
                    }
                } 
            }
        }

        protected bool ValidateInputOperation(TimeSpan timeout) 
        {
            if (timeout < TimeSpan.Zero) 
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("timeout", timeout,
                    SR.SFxTimeoutOutOfRange0)); 
            }

            return this.ThrowIfNotOpenedAndNotMasking(MaskingMode.All, false);
        } 

        protected bool ValidateOutputOperation(Message message, TimeSpan timeout, MaskingMode maskingMode) 
        { 
            if (message == null)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("message");
            }

            if (timeout < TimeSpan.Zero) 
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("timeout", timeout, 
                    SR.SFxTimeoutOutOfRange0)); 
            }
 
            return this.ThrowIfNotOpenedAndNotMasking(maskingMode, true);
        }

        internal void WaitForPendingOperations(TimeSpan timeout) 
        {
            this.synchronizer.WaitForPendingOperations(timeout); 
        } 

        protected RequestContext WrapMessage(Message message) 
        {
            if (message == null)
            {
                return null; 
            }
 
            return new MessageRequestContext(this, message); 
        }
 
        public RequestContext WrapRequestContext(RequestContext context)
        {
            if (context == null)
            { 
                return null;
            } 
 
            if (!this.TolerateFaults && this.defaultMaskingMode == MaskingMode.None)
            { 
                return context;
            }

            return new RequestRequestContext(this, context, context.RequestMessage); 
        }
 
        sealed class BinderCompletedAsyncResult : CompletedAsyncResult 
        {
            public BinderCompletedAsyncResult(AsyncCallback callback, object state) 
                : base(callback, state)
            {
            }
 
            public void End()
            { 
                CompletedAsyncResult.End(this); 
            }
        } 

        abstract class BinderRequestContext : RequestContextBase
        {
            ReliableChannelBinder binder; 
            MaskingMode maskingMode;
 
            public BinderRequestContext(ReliableChannelBinder binder, Message message) 
                : base(message, binder.defaultCloseTimeout, binder.defaultSendTimeout)
            { 
                if (binder == null)
                {
                    DiagnosticUtility.DebugAssert("Argument binder cannot be null.");
                } 

                this.binder = binder; 
                this.maskingMode = binder.defaultMaskingMode; 
            }
 
            protected ReliableChannelBinder Binder
            {
                get
                { 
                    return this.binder;
                } 
            } 

            protected MaskingMode MaskingMode 
            {
                get
                {
                    return this.maskingMode; 
                }
            } 
 
            public void SetMaskingMode(MaskingMode maskingMode)
            { 
                if (this.binder.defaultMaskingMode != MaskingMode.All)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException());
                } 

                this.maskingMode = maskingMode; 
            } 
        }
 
        protected class ChannelSynchronizer
        {
            bool aborting; // Indicates the current channel is being aborted, not the synchronizer.
            ReliableChannelBinder binder; 
            int count = 0;
            TChannel currentChannel; 
            InterruptibleWaitObject drainEvent; 
            static WaitCallback asyncGetChannelCallback = new WaitCallback(AsyncGetChannelCallback);
            TolerateFaultsMode faultMode; 
            Queue getChannelQueue;
            bool innerChannelFaulted;
            EventHandler onChannelFaulted;
            State state = State.Created; 
            bool tolerateFaults = true;
            object thisLock = new object(); 
            Queue waitQueue; 

            public ChannelSynchronizer(ReliableChannelBinder binder, TChannel channel, 
                TolerateFaultsMode faultMode)
            {
                this.binder = binder;
                this.currentChannel = channel; 
                this.faultMode = faultMode;
            } 
 
            public bool Aborting
            { 
                get
                {
                    return this.aborting;
                } 
            }
 
            public bool Connected 
            {
                get 
                {
                    return (this.state == State.ChannelOpened ||
                        this.state == State.ChannelOpening);
                } 
            }
 
            public TChannel CurrentChannel 
            {
                get 
                {
                    return this.currentChannel;
                }
            } 

            object ThisLock 
            { 
                get
                { 
                    return this.thisLock;
                }
            }
 
            public bool TolerateFaults
            { 
                get 
                {
                    return this.tolerateFaults; 
                }
            }

            // Server only API. 
            public TChannel AbortCurentChannel()
            { 
                lock (this.ThisLock) 
                {
                    if (!this.tolerateFaults) 
                    {
                        DiagnosticUtility.DebugAssert("It is only valid to abort the current channel when masking faults");
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false);
                    } 

                    if (this.state == State.ChannelOpening) 
                    { 
                        this.aborting = true;
                    } 
                    else if (this.state == State.ChannelOpened)
                    {
                        if (this.count == 0)
                        { 
                            this.state = State.NoChannel;
                        } 
                        else 
                        {
                            this.aborting = true; 
                            this.state = State.ChannelClosing;
                        }
                    }
                    else 
                    {
                        return null; 
                    } 

                    return this.currentChannel; 
                }
            }

            static void AsyncGetChannelCallback(object state) 
            {
                AsyncWaiter waiter = (AsyncWaiter)state; 
                waiter.GetChannel(false); 
            }
 
            public IAsyncResult BeginTryGetChannelForInput(bool canGetChannel, TimeSpan timeout,
                AsyncCallback callback, object state)
            {
                return this.BeginTryGetChannel(canGetChannel, false, timeout, MaskingMode.All, 
                    callback, state);
            } 
 
            public IAsyncResult BeginTryGetChannelForOutput(TimeSpan timeout,
                MaskingMode maskingMode, AsyncCallback callback, object state) 
            {
                return this.BeginTryGetChannel(true, true, timeout, maskingMode,
                    callback, state);
            } 

            IAsyncResult BeginTryGetChannel(bool canGetChannel, bool canCauseFault, 
                TimeSpan timeout, MaskingMode maskingMode, AsyncCallback callback, object state) 
            {
                TChannel channel = null; 
                AsyncWaiter waiter = null;
                bool getChannel = false;
                bool faulted = false;
 
                lock (this.ThisLock)
                { 
                    if (!this.ThrowIfNecessary(maskingMode)) 
                    {
                        channel = null; 
                    }
                    else if (this.state == State.ChannelOpened)
                    {
                        if (this.currentChannel == null) 
                        {
                            DiagnosticUtility.DebugAssert("Field currentChannel cannot be null in the ChannelOpened state."); 
                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); 
                        }
 
                        this.count++;
                        channel = this.currentChannel;
                    }
                    else if (!this.tolerateFaults 
                        && ((this.state == State.NoChannel)
                        || (this.state == State.ChannelClosing))) 
                    { 
                        if (canCauseFault)
                        { 
                            faulted = true;
                        }

                        channel = null; 
                    }
                    else if (!canGetChannel 
                        || (this.state == State.ChannelOpening) 
                        || (this.state == State.ChannelClosing))
                    { 
                        waiter = new AsyncWaiter(this, canGetChannel, null, timeout, maskingMode,
                            this.binder.ChannelParameters,
                            callback, state);
                        this.GetQueue(canGetChannel).Enqueue(waiter); 
                    }
                    else 
                    { 
                        if (this.state != State.NoChannel)
                        { 
                            DiagnosticUtility.DebugAssert("The state must be NoChannel.");
                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false);
                        }
 
                        waiter = new AsyncWaiter(this, canGetChannel,
                            this.GetCurrentChannelIfCreated(), timeout, maskingMode, 
                            this.binder.ChannelParameters, 
                            callback, state);
 
                        this.state = State.ChannelOpening;
                        getChannel = true;
                    }
                } 

                if (faulted) 
                { 
                    this.binder.Fault(null);
                } 

                if (waiter == null)
                {
                    return new TypedCompletedAsyncResult(channel, callback, state); 
                }
 
                if (getChannel) 
                {
                    waiter.GetChannel(true); 
                }
                else
                {
                    waiter.Wait(); 
                }
 
                return waiter; 
            }
 
            public IAsyncResult BeginWaitForPendingOperations(TimeSpan timeout,
                AsyncCallback callback, object state)
            {
                lock (this.ThisLock) 
                {
                    if (this.drainEvent != null) 
                    { 
                        DiagnosticUtility.DebugAssert("The WaitForPendingOperations operation may only be invoked once.");
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); 
                    }

                    if (this.count > 0)
                    { 
                        this.drainEvent = new InterruptibleWaitObject(false, false);
                    } 
                } 

                if (this.drainEvent != null) 
                {
                    return this.drainEvent.BeginWait(timeout, callback, state);
                }
                else 
                {
                    return new SynchronizerCompletedAsyncResult(callback, state); 
                } 
            }
 
            bool CompleteSetChannel(IWaiter waiter, out TChannel channel)
            {
                if (waiter == null)
                { 
                    DiagnosticUtility.DebugAssert("Argument waiter cannot be null.");
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); 
                } 

                bool close = false; 

                lock (this.ThisLock)
                {
                    if (this.ValidateOpened()) 
                    {
                        channel = this.currentChannel; 
                        return true; 
                    }
                    else 
                    {
                        channel = null;
                        close = this.state == State.Closed;
                    } 
                }
 
                if (close) 
                {
                    waiter.Close(); 
                }
                else
                {
                    waiter.Fault(); 
                }
 
                return false; 
            }
 
            public bool EndTryGetChannel(IAsyncResult result, out TChannel channel)
            {
                AsyncWaiter waiter = result as AsyncWaiter;
 
                if (waiter != null)
                { 
                    return waiter.End(out channel); 
                }
                else 
                {
                    channel = TypedCompletedAsyncResult.End(result);
                    return true;
                } 
            }
 
            public void EndWaitForPendingOperations(IAsyncResult result) 
            {
                SynchronizerCompletedAsyncResult completedResult = 
                    result as SynchronizerCompletedAsyncResult;

                if (completedResult != null)
                { 
                    completedResult.End();
                } 
                else 
                {
                    this.drainEvent.EndWait(result); 
                }
            }

            // Client API only. 
            public bool EnsureChannel()
            { 
                bool fault = false; 

                lock (this.ThisLock) 
                {
                    if (this.ValidateOpened())
                    {
                        // This is called only during the RM CS phase. In this phase, there are 2 
                        // valid states between Request calls, ChannelOpened and NoChannel.
                        if (this.state == State.ChannelOpened) 
                        { 
                            return true;
                        } 

                        if (this.state != State.NoChannel)
                        {
                            DiagnosticUtility.DebugAssert("The caller may only invoke this EnsureChannel during the CreateSequence negotiation. ChannelOpening and ChannelClosing are invalid states during this phase of the negotiation."); 
                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false);
                        } 
 
                        if (!this.tolerateFaults)
                        { 
                            fault = true;
                        }
                        else
                        { 
                            if (this.GetCurrentChannelIfCreated() != null)
                            { 
                                return true; 
                            }
 
                            if (this.binder.TryGetChannel(TimeSpan.Zero))
                            {
                                if (this.currentChannel == null)
                                { 
                                    return false;
                                } 
 
                                return true;
                            } 
                        }
                    }
                }
 
                if (fault)
                { 
                    this.binder.Fault(null); 
                }
 
                return false;
            }

            IWaiter GetChannelWaiter() 
            {
                if ((this.getChannelQueue == null) || (this.getChannelQueue.Count == 0)) 
                { 
                    return null;
                } 

                return this.getChannelQueue.Dequeue();
            }
 
            // Must be called within lock (this.ThisLock)
            TChannel GetCurrentChannelIfCreated() 
            { 
                if (this.state != State.NoChannel)
                { 
                    DiagnosticUtility.DebugAssert("This method may only be called in the NoChannel state.");
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false);
                }
 
                if ((this.currentChannel != null)
                    && (this.currentChannel.State == CommunicationState.Created)) 
                { 
                    return this.currentChannel;
                } 
                else
                {
                    return null;
                } 
            }
 
            Queue GetQueue(bool canGetChannel) 
            {
                if (canGetChannel) 
                {
                    if (this.getChannelQueue == null)
                    {
                        this.getChannelQueue = new Queue(); 
                    }
 
                    return this.getChannelQueue; 
                }
                else 
                {
                    if (this.waitQueue == null)
                    {
                        this.waitQueue = new Queue(); 
                    }
 
                    return this.waitQueue; 
                }
            } 

            void OnChannelFaulted(object sender, EventArgs e)
            {
                TChannel faultedChannel = (TChannel)sender; 
                bool faultBinder = false;
                bool raiseInnerChannelFaulted = false; 
 
                lock (this.ThisLock)
                { 
                    if (this.currentChannel != faultedChannel)
                    {
                        return;
                    } 

                    // The synchronizer is already closed or aborted. 
                    if (!this.ValidateOpened()) 
                    {
                        return; 
                    }

                    if (this.state == State.ChannelOpened)
                    { 
                        if (this.count == 0)
                        { 
                            faultedChannel.Faulted -= this.onChannelFaulted; 
                        }
 
                        faultBinder = !this.tolerateFaults;
                        this.state = State.ChannelClosing;
                        this.innerChannelFaulted = true;
 
                        if (!faultBinder && this.count == 0)
                        { 
                            this.state = State.NoChannel; 
                            this.aborting = false;
                            raiseInnerChannelFaulted = true; 
                            this.innerChannelFaulted = false;
                        }
                    }
                } 

                if (faultBinder) 
                { 
                    this.binder.Fault(null);
                } 

                faultedChannel.Abort();

                if (raiseInnerChannelFaulted) 
                {
                    this.binder.OnInnerChannelFaulted(); 
                } 
            }
 
            bool OnChannelOpened(IWaiter waiter)
            {
                if (waiter == null)
                { 
                    DiagnosticUtility.DebugAssert("Argument waiter cannot be null.");
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); 
                } 

                bool close = false; 
                bool fault = false;

                Queue temp1 = null;
                Queue temp2 = null; 
                TChannel channel = null;
 
                lock (this.ThisLock) 
                {
                    if (this.currentChannel == null) 
                    {
                        DiagnosticUtility.DebugAssert("Caller must ensure that field currentChannel is set before opening the channel.");
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false);
                    } 

                    if (this.ValidateOpened()) 
                    { 
                        if (this.state != State.ChannelOpening)
                        { 
                            DiagnosticUtility.DebugAssert("This method may only be called in the ChannelOpening state.");
                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false);
                        }
 
                        this.state = State.ChannelOpened;
                        this.SetTolerateFaults(); 
 
                        this.count += 1;
                        this.count += (this.getChannelQueue == null) ? 0 : this.getChannelQueue.Count; 
                        this.count += (this.waitQueue == null) ? 0 : this.waitQueue.Count;

                        temp1 = this.getChannelQueue;
                        temp2 = this.waitQueue; 
                        channel = this.currentChannel;
 
                        this.getChannelQueue = null; 
                        this.waitQueue = null;
                    } 
                    else
                    {
                        close = this.state == State.Closed;
                        fault = this.state == State.Faulted; 
                    }
                } 
 
                if (close)
                { 
                    waiter.Close();
                    return false;
                }
                else if (fault) 
                {
                    waiter.Fault(); 
                    return false; 
                }
 
                this.SetWaiters(temp1, channel);
                this.SetWaiters(temp2, channel);
                return true;
            } 

            void OnGetChannelFailed() 
            { 
                IWaiter waiter = null;
 
                lock (this.ThisLock)
                {
                    if (!this.ValidateOpened())
                    { 
                        return;
                    } 
 
                    if (this.state != State.ChannelOpening)
                    { 
                        DiagnosticUtility.DebugAssert("The state must be set to ChannelOpening before the caller attempts to open the channel.");
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false);
                    }
 
                    waiter = this.GetChannelWaiter();
 
                    if (waiter == null) 
                    {
                        this.state = State.NoChannel; 
                        return;
                    }
                }
 
                if (waiter is SyncWaiter)
                { 
                    waiter.GetChannel(false); 
                }
                else 
                {
                    IOThreadScheduler.ScheduleCallback(asyncGetChannelCallback, waiter);
                }
            } 

            public void OnReadEof() 
            { 
                lock (this.ThisLock)
                { 
                    if (this.count <= 0)
                    {
                        DiagnosticUtility.DebugAssert("Caller must ensure that OnReadEof is called before ReturnChannel.");
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); 
                    }
 
                    if (this.ValidateOpened()) 
                    {
                        if ((this.state != State.ChannelOpened) && (this.state != State.ChannelClosing)) 
                        {
                            DiagnosticUtility.DebugAssert("Since count is positive, the only valid states are ChannelOpened and ChannelClosing.");
                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false);
                        } 

                        if (this.currentChannel.State != CommunicationState.Faulted) 
                        { 
                            this.state = State.ChannelClosing;
                        } 
                    }
                }
            }
 
            bool RemoveWaiter(IWaiter waiter)
            { 
                Queue waiters = waiter.CanGetChannel ? this.getChannelQueue : this.waitQueue; 
                bool removed = false;
 
                lock (this.ThisLock)
                {
                    if (!this.ValidateOpened())
                    { 
                        return false;
                    } 
 
                    for (int i = waiters.Count; i > 0; i--)
                    { 
                        IWaiter temp = waiters.Dequeue();

                        if (object.ReferenceEquals(waiter, temp))
                        { 
                            removed = true;
                        } 
                        else 
                        {
                            waiters.Enqueue(temp); 
                        }
                    }
                }
 
                return removed;
            } 
 
            public void ReturnChannel()
            { 
                TChannel channel = null;
                IWaiter waiter = null;
                bool faultBinder = false;
                bool drained; 
                bool raiseInnerChannelFaulted = false;
 
                lock (this.ThisLock) 
                {
                    if (this.count <= 0) 
                    {
                        DiagnosticUtility.DebugAssert("Method ReturnChannel() can only be called after TryGetChannel or EndTryGetChannel returns a channel.");
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false);
                    } 

                    this.count--; 
                    drained = (this.count == 0) && (this.drainEvent != null); 

                    if (this.ValidateOpened()) 
                    {
                        if ((this.state != State.ChannelOpened) && (this.state != State.ChannelClosing))
                        {
                            DiagnosticUtility.DebugAssert("ChannelOpened and ChannelClosing are the only 2 valid states when count is positive."); 
                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false);
                        } 
 
                        if (this.currentChannel.State == CommunicationState.Faulted)
                        { 
                            faultBinder = !this.tolerateFaults;
                            this.innerChannelFaulted = true;
                            this.state = State.ChannelClosing;
                        } 

                        if (!faultBinder && (this.state == State.ChannelClosing) && (this.count == 0)) 
                        { 
                            channel = this.currentChannel;
                            raiseInnerChannelFaulted = this.innerChannelFaulted; 
                            this.innerChannelFaulted = false;

                            this.state = State.NoChannel;
                            this.aborting = false; 

                            waiter = this.GetChannelWaiter(); 
 
                            if (waiter != null)
                            { 
                                this.state = State.ChannelOpening;
                            }
                        }
                    } 
                }
 
                if (faultBinder) 
                {
                    this.binder.Fault(null); 
                }

                if (drained)
                { 
                    this.drainEvent.Set();
                } 
 
                if (channel != null)
                { 
                    channel.Faulted -= this.onChannelFaulted;

                    if (channel.State == CommunicationState.Opened)
                    { 
                        this.binder.CloseChannel(channel);
                    } 
                    else 
                    {
                        channel.Abort(); 
                    }

                    if (waiter != null)
                    { 
                        waiter.GetChannel(false);
                    } 
                } 

                if (raiseInnerChannelFaulted) 
                {
                    this.binder.OnInnerChannelFaulted();
                }
            } 

            public bool SetChannel(TChannel channel) 
            { 
                lock (this.ThisLock)
                { 
                    if (this.state != State.ChannelOpening && this.state != State.NoChannel)
                    {
                        DiagnosticUtility.DebugAssert("SetChannel is only valid in the NoChannel and ChannelOpening states");
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); 
                    }
 
                    if (!this.tolerateFaults) 
                    {
                        DiagnosticUtility.DebugAssert("SetChannel is only valid when masking faults"); 
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false);
                    }

                    if (this.ValidateOpened()) 
                    {
                        this.currentChannel = channel; 
                        return true; 
                    }
                    else 
                    {
                        return false;
                    }
                } 
            }
 
            void SetTolerateFaults() 
            {
                if (this.faultMode == TolerateFaultsMode.Never) 
                {
                    this.tolerateFaults = false;
                }
                else if (this.faultMode == TolerateFaultsMode.IfNotSecuritySession) 
                {
                    this.tolerateFaults = !this.binder.HasSecuritySession(this.currentChannel); 
                } 

                if (this.onChannelFaulted == null) 
                {
                    this.onChannelFaulted = new EventHandler(this.OnChannelFaulted);
                }
 
                this.currentChannel.Faulted += this.onChannelFaulted;
            } 
 
            void SetWaiters(Queue waiters, TChannel channel)
            { 
                if ((waiters != null) && (waiters.Count > 0))
                {
                    foreach (IWaiter waiter in waiters)
                    { 
                        waiter.Set(channel);
                    } 
                } 
            }
 
            public void StartSynchronizing()
            {
                lock (this.ThisLock)
                { 
                    if (this.state == State.Created)
                    { 
                        this.state = State.NoChannel; 
                    }
                    else 
                    {
                        if (this.state != State.Closed)
                        {
                            DiagnosticUtility.DebugAssert("Abort is the only operation that can race with Open."); 
                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false);
                        } 
 
                        return;
                    } 

                    if (this.currentChannel == null)
                    {
                        if (!this.binder.TryGetChannel(TimeSpan.Zero)) 
                        {
                            return; 
                        } 
                    }
 
                    if (this.currentChannel == null)
                    {
                        return;
                    } 

                    if (!this.binder.MustOpenChannel) 
                    { 
                        // Channel is already opened.
                        this.state = State.ChannelOpened; 
                        this.SetTolerateFaults();
                    }
                }
            } 

            public TChannel StopSynchronizing(bool close) 
            { 
                lock (this.ThisLock)
                { 
                    if ((this.state != State.Faulted) && (this.state != State.Closed))
                    {
                        this.state = close ? State.Closed : State.Faulted;
 
                        if ((this.currentChannel != null) && (this.onChannelFaulted != null))
                        { 
                            this.currentChannel.Faulted -= this.onChannelFaulted; 
                        }
                    } 

                    return this.currentChannel;
                }
            } 

            // Must be called under a lock. 
            bool ThrowIfNecessary(MaskingMode maskingMode) 
            {
                if (this.ValidateOpened()) 
                {
                    return true;
                }
 
                // state is Closed or Faulted.
                Exception e; 
 
                if (this.state == State.Closed)
                { 
                    e = this.binder.GetClosedException(maskingMode);
                }
                else
                { 
                    e = this.binder.GetFaultedException(maskingMode);
                } 
 
                if (e != null)
                { 
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(e);
                }

                return false; 
            }
 
            public bool TryGetChannelForInput(bool canGetChannel, TimeSpan timeout, 
                out TChannel channel)
            { 
                return this.TryGetChannel(canGetChannel, false, timeout, MaskingMode.All,
                    out channel);
            }
 
            public bool TryGetChannelForOutput(TimeSpan timeout, MaskingMode maskingMode,
                out TChannel channel) 
            { 
                return this.TryGetChannel(true, true, timeout, maskingMode, out channel);
            } 

            bool TryGetChannel(bool canGetChannel, bool canCauseFault, TimeSpan timeout,
                MaskingMode maskingMode, out TChannel channel)
            { 
                SyncWaiter waiter = null;
                bool faulted = false; 
                bool getChannel = false; 

                lock (this.ThisLock) 
                {
                    if (!this.ThrowIfNecessary(maskingMode))
                    {
                        channel = null; 
                        return true;
                    } 
 
                    if (this.state == State.ChannelOpened)
                    { 
                        if (this.currentChannel == null)
                        {
                            DiagnosticUtility.DebugAssert("Field currentChannel cannot be null in the ChannelOpened state.");
                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); 
                        }
 
                        this.count++; 
                        channel = this.currentChannel;
                        return true; 
                    }

                    if (!this.tolerateFaults
                        && ((this.state == State.ChannelClosing) 
                        || (this.state == State.NoChannel)))
                    { 
                        if (!canCauseFault) 
                        {
                            channel = null; 
                            return true;
                        }

                        faulted = true; 
                    }
                    else if (!canGetChannel 
                        || (this.state == State.ChannelOpening) 
                        || (this.state == State.ChannelClosing))
                    { 
                        waiter = new SyncWaiter(this, canGetChannel, null, timeout, maskingMode, this.binder.ChannelParameters);
                        this.GetQueue(canGetChannel).Enqueue(waiter);
                    }
                    else 
                    {
                        if (this.state != State.NoChannel) 
                        { 
                            DiagnosticUtility.DebugAssert("The state must be NoChannel.");
                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); 
                        }

                        waiter = new SyncWaiter(this, canGetChannel,
                            this.GetCurrentChannelIfCreated(), timeout, maskingMode, 
                            this.binder.ChannelParameters);
 
                        this.state = State.ChannelOpening; 
                        getChannel = true;
                    } 
                }

                if (faulted)
                { 
                    this.binder.Fault(null);
                    channel = null; 
                    return true; 
                }
 
                if (getChannel)
                {
                    waiter.GetChannel(true);
                } 

                return waiter.TryWait(out channel); 
            } 

            public void UnblockWaiters() 
            {
                Queue temp1;
                Queue temp2;
 
                lock (this.ThisLock)
                { 
                    temp1 = this.getChannelQueue; 
                    temp2 = this.waitQueue;
 
                    this.getChannelQueue = null;
                    this.waitQueue = null;
                }
 
                bool close = this.state == State.Closed;
                this.UnblockWaiters(temp1, close); 
                this.UnblockWaiters(temp2, close); 
            }
 
            void UnblockWaiters(Queue waiters, bool close)
            {
                if ((waiters != null) && (waiters.Count > 0))
                { 
                    foreach (IWaiter waiter in waiters)
                    { 
                        if (close) 
                        {
                            waiter.Close(); 
                        }
                        else
                        {
                            waiter.Fault(); 
                        }
                    } 
                } 
            }
 
            bool ValidateOpened()
            {
                if (this.state == State.Created)
                { 
                    DiagnosticUtility.DebugAssert("This operation expects that the synchronizer has been opened.");
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); 
                } 

                return (this.state != State.Closed) && (this.state != State.Faulted); 
            }

            public void WaitForPendingOperations(TimeSpan timeout)
            { 
                lock (this.ThisLock)
                { 
                    if (this.drainEvent != null) 
                    {
                        DiagnosticUtility.DebugAssert("The WaitForPendingOperations operation may only be invoked once."); 
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false);
                    }

                    if (this.count > 0) 
                    {
                        this.drainEvent = new InterruptibleWaitObject(false, false); 
                    } 
                }
 
                if (this.drainEvent != null)
                {
                    this.drainEvent.Wait(timeout);
                } 
            }
 
            enum State 
            {
                Created, 
                NoChannel,
                ChannelOpening,
                ChannelOpened,
                ChannelClosing, 
                Faulted,
                Closed 
            } 

            public interface IWaiter 
            {
                bool CanGetChannel { get; }

                void Close(); 
                void Fault();
                void GetChannel(bool onUserThread); 
                void Set(TChannel channel); 
            }
 
            public sealed class AsyncWaiter : AsyncResult, IWaiter
            {
                bool canGetChannel;
                TChannel channel; 
                ChannelParameterCollection channelParameters;
                bool isSynchronous = true; 
                MaskingMode maskingMode; 
                static AsyncCallback onOpenComplete = DiagnosticUtility.ThunkAsyncCallback(new AsyncCallback(OnOpenComplete));
                static WaitCallback onTimeoutElapsed = new WaitCallback(OnTimeoutElapsed); 
                static AsyncCallback onTryGetChannelComplete = DiagnosticUtility.ThunkAsyncCallback(new AsyncCallback(OnTryGetChannelComplete));
                bool timedOut = false;
                ChannelSynchronizer synchronizer;
                TimeoutHelper timeoutHelper; 
                IOThreadTimer timer;
                bool timerCancelled = false; 
 
                public AsyncWaiter(ChannelSynchronizer synchronizer, bool canGetChannel,
                    TChannel channel, TimeSpan timeout, MaskingMode maskingMode, 
                    ChannelParameterCollection channelParameters,
                    AsyncCallback callback, object state)
                    : base(callback, state)
                { 
                    if (!canGetChannel)
                    { 
                        if (channel != null) 
                        {
                            DiagnosticUtility.DebugAssert("This waiter must wait for a channel thus argument channel must be null."); 
                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false);
                        }
                    }
 
                    this.synchronizer = synchronizer;
                    this.canGetChannel = canGetChannel; 
                    this.channel = channel; 
                    this.timeoutHelper = new TimeoutHelper(timeout);
                    this.maskingMode = maskingMode; 
                    this.channelParameters = channelParameters;
                }

                public bool CanGetChannel 
                {
                    get 
                    { 
                        return this.canGetChannel;
                    } 
                }

                object ThisLock
                { 
                    get
                    { 
                        return this; 
                    }
                } 

                void CancelTimer()
                {
                    lock (this.ThisLock) 
                    {
                        if (!this.timerCancelled) 
                        { 
                            if (this.timer != null)
                            { 
                                this.timer.Cancel();
                            }

                            this.timerCancelled = true; 
                        }
                    } 
                } 

                public void Close() 
                {
                    this.CancelTimer();
                    this.channel = null;
                    this.Complete(false, 
                        this.synchronizer.binder.GetClosedException(this.maskingMode));
                } 
 
                bool CompleteOpen(IAsyncResult result)
                { 
                    this.channel.EndOpen(result);
                    return this.OnChannelOpened();
                }
 
                bool CompleteTryGetChannel(IAsyncResult result)
                { 
                    if (!this.synchronizer.binder.EndTryGetChannel(result)) 
                    {
                        this.timedOut = true; 
                        this.OnGetChannelFailed();
                        return true;
                    }
 
                    if (!this.synchronizer.CompleteSetChannel(this, out this.channel))
                    { 
                        if (!this.IsCompleted) 
                        {
                            DiagnosticUtility.DebugAssert("CompleteSetChannel must complete the IWaiter if it returns false."); 
                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false);
                        }

                        return false; 
                    }
 
                    return this.OpenChannel(); 
                }
 
                public bool End(out TChannel channel)
                {
                    AsyncResult.End(this);
                    channel = this.channel; 
                    return !this.timedOut;
                } 
 
                public void Fault()
                { 
                    this.CancelTimer();
                    this.channel = null;
                    this.Complete(false,
                        this.synchronizer.binder.GetFaultedException(this.maskingMode)); 
                }
 
                bool GetChannel() 
                {
                    if (this.channel != null) 
                    {
                        return this.OpenChannel();
                    }
                    else 
                    {
                        IAsyncResult result = this.synchronizer.binder.BeginTryGetChannel( 
                            this.timeoutHelper.RemainingTime(), onTryGetChannelComplete, this); 

                        if (result.CompletedSynchronously) 
                        {
                            return this.CompleteTryGetChannel(result);
                        }
                    } 

                    return false; 
                } 

                public void GetChannel(bool onUserThread) 
                {
                    if (!this.CanGetChannel)
                    {
                        DiagnosticUtility.DebugAssert("This waiter must wait for a channel thus the caller cannot attempt to get a channel."); 
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false);
                    } 
 
                    this.isSynchronous = onUserThread;
 
                    if (onUserThread)
                    {
                        bool throwing = true;
 
                        try
                        { 
                            if (this.GetChannel()) 
                            {
                                this.Complete(true); 
                            }

                            throwing = false;
                        } 
                        finally
                        { 
                            if (throwing) 
                            {
                                this.OnGetChannelFailed(); 
                            }
                        }
                    }
                    else 
                    {
                        bool complete = false; 
                        Exception completeException = null; 

                        try 
                        {
                            this.CancelTimer();
                            complete = this.GetChannel();
                        } 
#pragma warning suppress 56500 // covered by FxCOP
                        catch (Exception e) 
                        { 
                            if (DiagnosticUtility.IsFatal(e))
                            { 
                                throw;
                            }

                            this.OnGetChannelFailed(); 
                            completeException = e;
                        } 
 
                        if (complete || completeException != null)
                        { 
                            this.Complete(false, completeException);
                        }
                    }
                } 

                bool OnChannelOpened() 
                { 
                    if (this.synchronizer.OnChannelOpened(this))
                    { 
                        return true;
                    }
                    else
                    { 
                        if (!this.IsCompleted)
                        { 
                            DiagnosticUtility.DebugAssert("OnChannelOpened must complete the IWaiter if it returns false."); 
                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false);
                        } 

                        return false;
                    }
                } 

                void OnGetChannelFailed() 
                { 
                    if (this.channel != null)
                    { 
                        this.channel.Abort();
                    }

                    this.synchronizer.OnGetChannelFailed(); 
                }
 
                static void OnOpenComplete(IAsyncResult result) 
                {
                    if (!result.CompletedSynchronously) 
                    {
                        AsyncWaiter waiter = (AsyncWaiter)result.AsyncState;
                        bool complete = false;
                        Exception completeException = null; 

                        waiter.isSynchronous = false; 
 
                        try
                        { 
                            complete = waiter.CompleteOpen(result);
                        }
#pragma warning suppress 56500 // covered by FxCOP
                        catch (Exception e) 
                        {
                            if (DiagnosticUtility.IsFatal(e)) 
                            { 
                                throw;
                            } 

                            completeException = e;
                        }
 
                        if (complete)
                        { 
                            waiter.Complete(false); 
                        }
                        else if (completeException != null) 
                        {
                            waiter.OnGetChannelFailed();
                            waiter.Complete(false, completeException);
                        } 
                    }
                } 
 
                void OnTimeoutElapsed()
                { 
                    if (this.synchronizer.RemoveWaiter(this))
                    {
                        this.timedOut = true;
                        this.Complete(this.isSynchronous, null); 
                    }
                } 
 
                static void OnTimeoutElapsed(object state)
                { 
                    AsyncWaiter waiter = (AsyncWaiter)state;
                    waiter.isSynchronous = false;
                    waiter.OnTimeoutElapsed();
                } 

                static void OnTryGetChannelComplete(IAsyncResult result) 
                { 
                    if (!result.CompletedSynchronously)
                    { 
                        AsyncWaiter waiter = (AsyncWaiter)result.AsyncState;
                        waiter.isSynchronous = false;
                        bool complete = false;
                        Exception completeException = null; 

                        try 
                        { 
                            complete = waiter.CompleteTryGetChannel(result);
                        } 
#pragma warning suppress 56500 // covered by FxCOP
                        catch (Exception e)
                        {
                            if (DiagnosticUtility.IsFatal(e)) 
                            {
                                throw; 
                            } 

                            completeException = e; 
                        }

                        if (complete || completeException != null)
                        { 
                            if (completeException != null)
                                waiter.OnGetChannelFailed(); 
                            waiter.Complete(waiter.isSynchronous, completeException); 
                        }
                    } 
                }

                bool OpenChannel()
                { 
                    if (this.synchronizer.binder.MustOpenChannel)
                    { 
                        if (this.channelParameters != null) 
                        {
                            this.channelParameters.PropagateChannelParameters(this.channel); 
                        }

                        IAsyncResult result = this.channel.BeginOpen(
                            this.timeoutHelper.RemainingTime(), onOpenComplete, this); 

                        if (result.CompletedSynchronously) 
                        { 
                            return this.CompleteOpen(result);
                        } 

                        return false;
                    }
                    else 
                    {
                        return this.OnChannelOpened(); 
                    } 
                }
 
                public void Set(TChannel channel)
                {
                    this.CancelTimer();
                    this.channel = channel; 
                    this.Complete(false);
                } 
 
                // Always called from the user's thread.
                public void Wait() 
                {
                    lock (this.ThisLock)
                    {
                        if (this.timerCancelled) 
                        {
                            return; 
                        } 

                        TimeSpan timeout = this.timeoutHelper.RemainingTime(); 

                        if (timeout > TimeSpan.Zero)
                        {
                            this.timer = new IOThreadTimer(onTimeoutElapsed, this, true); 
                            this.timer.Set(this.timeoutHelper.RemainingTime());
                            return; 
                        } 
                    }
 
                    this.OnTimeoutElapsed();
                }
            }
 
            sealed class SynchronizerCompletedAsyncResult : CompletedAsyncResult
            { 
                public SynchronizerCompletedAsyncResult(AsyncCallback callback, object state) 
                    : base(callback, state)
                { 
                }

                public void End()
                { 
                    CompletedAsyncResult.End(this);
                } 
            } 

            sealed class SyncWaiter : IWaiter 
            {
                bool canGetChannel;
                TChannel channel;
                ChannelParameterCollection channelParameters; 
                AutoResetEvent completeEvent = new AutoResetEvent(false);
                Exception exception; 
                bool getChannel = false; 
                MaskingMode maskingMode;
                ChannelSynchronizer synchronizer; 
                TimeoutHelper timeoutHelper;

                public SyncWaiter(ChannelSynchronizer synchronizer, bool canGetChannel,
                    TChannel channel, TimeSpan timeout, MaskingMode maskingMode, 
                    ChannelParameterCollection channelParameters)
                { 
                    if (!canGetChannel) 
                    {
                        if (channel != null) 
                        {
                            DiagnosticUtility.DebugAssert("This waiter must wait for a channel thus argument channel must be null.");
                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false);
                        } 
                    }
 
                    this.synchronizer = synchronizer; 
                    this.canGetChannel = canGetChannel;
                    this.channel = channel; 
                    this.timeoutHelper = new TimeoutHelper(timeout);
                    this.maskingMode = maskingMode;
                    this.channelParameters = channelParameters;
                } 

                public bool CanGetChannel 
                { 
                    get
                    { 
                        return this.canGetChannel;
                    }
                }
 
                public void Close()
                { 
                    this.exception = this.synchronizer.binder.GetClosedException(this.maskingMode); 
                    this.completeEvent.Set();
                } 

                public void Fault()
                {
                    this.exception = this.synchronizer.binder.GetFaultedException(this.maskingMode); 
                    this.completeEvent.Set();
                } 
 
                public void GetChannel(bool onUserThread)
                { 
                    if (!this.CanGetChannel)
                    {
                        DiagnosticUtility.DebugAssert("This waiter must wait for a channel thus the caller cannot attempt to get a channel.");
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); 
                    }
 
                    this.getChannel = true; 
                    this.completeEvent.Set();
                } 

                public void Set(TChannel channel)
                {
                    if (channel == null) 
                    {
                        DiagnosticUtility.DebugAssert("Argument channel cannot be null. Caller must call Fault or Close instead."); 
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); 
                    }
 
                    this.channel = channel;
                    this.completeEvent.Set();
                }
 
                bool TryGetChannel()
                { 
                    TChannel channel; 

                    if (this.channel != null) 
                    {
                        channel = this.channel;
                    }
                    else if (this.synchronizer.binder.TryGetChannel( 
                        this.timeoutHelper.RemainingTime()))
                    { 
                        if (!this.synchronizer.CompleteSetChannel(this, out channel)) 
                        {
                            return true; 
                        }
                    }
                    else
                    { 
                        this.synchronizer.OnGetChannelFailed();
                        return false; 
                    } 

                    if (this.synchronizer.binder.MustOpenChannel) 
                    {
                        bool throwing = true;

                        if (this.channelParameters != null) 
                        {
                            this.channelParameters.PropagateChannelParameters(channel); 
                        } 

                        try 
                        {
                            channel.Open(this.timeoutHelper.RemainingTime());
                            throwing = false;
                        } 
                        finally
                        { 
                            if (throwing) 
                            {
                                channel.Abort(); 
                                this.synchronizer.OnGetChannelFailed();
                            }
                        }
                    } 

                    if (this.synchronizer.OnChannelOpened(this)) 
                    { 
                        this.Set(channel);
                    } 

                    return true;
                }
 
                public bool TryWait(out TChannel channel)
                { 
                    if (!this.Wait()) 
                    {
                        channel = null; 
                        return false;
                    }
                    else if (this.getChannel && !this.TryGetChannel())
                    { 
                        channel = null;
                        return false; 
                    } 

                    this.completeEvent.Close(); 

                    if (this.exception != null)
                    {
                        if (this.channel != null) 
                        {
                            DiagnosticUtility.DebugAssert("User of IWaiter called both Set and Fault or Close."); 
                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); 
                        }
 
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(this.exception);
                    }

                    channel = this.channel; 
                    return true;
                } 
 
                bool Wait()
                { 
                    if (!TimeoutHelper.WaitOne(this.completeEvent,
                          this.timeoutHelper.RemainingTime(), false))
                    {
                        if (this.synchronizer.RemoveWaiter(this)) 
                        {
                            return false; 
                        } 
                        else
                        { 
                            TimeoutHelper.WaitOne(this.completeEvent, TimeSpan.MaxValue, false);
                        }
                    }
 
                    return true;
                } 
            } 
        }
 
        sealed class CloseAsyncResult : AsyncResult
        {
            ReliableChannelBinder binder;
            TChannel channel; 
            MaskingMode maskingMode;
            static AsyncCallback onBinderCloseComplete = DiagnosticUtility.ThunkAsyncCallback(new AsyncCallback(OnBinderCloseComplete)); 
            static AsyncCallback onChannelCloseComplete = DiagnosticUtility.ThunkAsyncCallback(new AsyncCallback(OnChannelCloseComplete)); 
            TimeoutHelper timeoutHelper;
 
            public CloseAsyncResult(ReliableChannelBinder binder, TChannel channel,
                TimeSpan timeout, MaskingMode maskingMode, AsyncCallback callback, object state)
                : base(callback, state)
            { 
                this.binder = binder;
                this.channel = channel; 
                this.timeoutHelper = new TimeoutHelper(timeout); 
                this.maskingMode = maskingMode;
                bool complete = false; 

                try
                {
                    this.binder.OnShutdown(); 
                    IAsyncResult result = this.binder.OnBeginClose(timeout, onBinderCloseComplete, this);
 
                    if (result.CompletedSynchronously) 
                    {
                        complete = this.CompleteBinderClose(true, result); 
                    }
                }
                catch (Exception e)
                { 
                    if (DiagnosticUtility.IsFatal(e))
                    { 
                        throw; 
                    }
 
                    this.binder.Abort();

                    if (!this.binder.HandleException(e, this.maskingMode))
                    { 
                        throw;
                    } 
                    else 
                    {
                        complete = true; 
                    }
                }

                if (complete) 
                {
                    this.Complete(true); 
                } 
            }
 
            bool CompleteBinderClose(bool synchronous, IAsyncResult result)
            {
                this.binder.OnEndClose(result);
 
                if (this.channel != null)
                { 
                    result = this.binder.BeginCloseChannel(this.channel, 
                        this.timeoutHelper.RemainingTime(), onChannelCloseComplete, this);
 
                    if (result.CompletedSynchronously)
                    {
                        return this.CompleteChannelClose(synchronous, result);
                    } 
                    else
                    { 
                        return false; 
                    }
                } 
                else
                {
                    this.binder.TransitionToClosed();
                    return true; 
                }
            } 
 
            bool CompleteChannelClose(bool synchronous, IAsyncResult result)
            { 
                this.binder.EndCloseChannel(this.channel, result);
                this.binder.TransitionToClosed();
                return true;
            } 

            public void End() 
            { 
                AsyncResult.End(this);
            } 

            Exception HandleAsyncException(Exception e)
            {
                this.binder.Abort(); 

                if (this.binder.HandleException(e, this.maskingMode)) 
                { 
                    return null;
                } 
                else
                {
                    return e;
                } 
            }
 
            static void OnBinderCloseComplete(IAsyncResult result) 
            {
                if (!result.CompletedSynchronously) 
                {
                    CloseAsyncResult closeResult = (CloseAsyncResult)result.AsyncState;
                    bool complete;
                    Exception completeException; 

                    try 
                    { 
                        complete = closeResult.CompleteBinderClose(false, result);
                        completeException = null; 
                    }
#pragma warning suppress 56500 // covered by FxCOP
                    catch (Exception e)
                    { 
                        if (DiagnosticUtility.IsFatal(e))
                        { 
                            throw; 
                        }
 
                        complete = true;
                        completeException = e;
                    }
 
                    if (complete)
                    { 
                        if (completeException != null) 
                        {
                            completeException = closeResult.HandleAsyncException(completeException); 
                        }

                        closeResult.Complete(false, completeException);
                    } 
                }
            } 
 
            static void OnChannelCloseComplete(IAsyncResult result)
            { 
                if (!result.CompletedSynchronously)
                {
                    CloseAsyncResult closeResult = (CloseAsyncResult)result.AsyncState;
                    bool complete; 
                    Exception completeException;
 
                    try 
                    {
                        complete = closeResult.CompleteChannelClose(false, result); 
                        completeException = null;
                    }
#pragma warning suppress 56500 // covered by FxCOP
                    catch (Exception e) 
                    {
                        if (DiagnosticUtility.IsFatal(e)) 
                        { 
                            throw;
                        } 

                        complete = true;
                        completeException = e;
                    } 

                    if (complete) 
                    { 
                        if (completeException != null)
                        { 
                            completeException = closeResult.HandleAsyncException(completeException);
                        }

                        closeResult.Complete(false, completeException); 
                    }
                } 
            } 
        }
 
        protected abstract class InputAsyncResult : AsyncResult
            where TBinder : ReliableChannelBinder
        {
            bool autoAborted; 
            TBinder binder;
            bool canGetChannel; 
            TChannel channel; 
            bool isSynchronous = true;
            MaskingMode maskingMode; 
            static AsyncCallback onInputComplete = DiagnosticUtility.ThunkAsyncCallback(new AsyncCallback(OnInputCompleteStatic));
            static AsyncCallback onTryGetChannelComplete = DiagnosticUtility.ThunkAsyncCallback(new AsyncCallback(OnTryGetChannelCompleteStatic));
            bool success;
            TimeoutHelper timeoutHelper; 

            public InputAsyncResult(TBinder binder, bool canGetChannel, TimeSpan timeout, 
                MaskingMode maskingMode, AsyncCallback callback, object state) 
                : base(callback, state)
            { 
                this.binder = binder;
                this.canGetChannel = canGetChannel;
                this.timeoutHelper = new TimeoutHelper(timeout);
                this.maskingMode = maskingMode; 
            }
 
            protected abstract IAsyncResult BeginInput(TBinder binder, TChannel channel, 
                TimeSpan timeout, AsyncCallback callback, object state);
 
            // returns true if the caller should retry
            bool CompleteInput(IAsyncResult result)
            {
                bool complete; 

                try 
                { 
                    this.success = this.EndInput(this.binder, this.channel, result, out complete);
                } 
                finally
                {
                    this.autoAborted = this.binder.Synchronizer.Aborting;
                    this.binder.synchronizer.ReturnChannel(); 
                }
 
                return !complete; 
            }
 
            // returns true if the caller should retry
            bool CompleteTryGetChannel(IAsyncResult result, out bool complete)
            {
                complete = false; 
                this.success = this.binder.synchronizer.EndTryGetChannel(result, out this.channel);
 
                // the synchronizer is faulted and not reestablishing or closed, or the call timed 
                // out, complete and don't retry.
                if (this.channel == null) 
                {
                    complete = true;
                    return false;
                } 

                bool throwing = true; 
                IAsyncResult inputResult = null; 

                try 
                {
                    inputResult = this.BeginInput(this.binder, this.channel,
                        this.timeoutHelper.RemainingTime(), onInputComplete, this);
                    throwing = false; 
                }
                finally 
                { 
                    if (throwing)
                    { 
                        this.autoAborted = this.binder.Synchronizer.Aborting;
                        this.binder.synchronizer.ReturnChannel();
                    }
                } 

                if (inputResult.CompletedSynchronously) 
                { 
                    if (this.CompleteInput(inputResult))
                    { 
                        complete = false;
                        return true;
                    }
                    else 
                    {
                        complete = true; 
                        return false; 
                    }
                } 
                else
                {
                    complete = false;
                    return false; 
                }
            } 
 
            public bool End()
            { 
                AsyncResult.End>(this);
                return this.success;
            }
 
            protected abstract bool EndInput(TBinder binder, TChannel channel,
                IAsyncResult result, out bool complete); 
 
            void OnInputComplete(IAsyncResult result)
            { 
                this.isSynchronous = false;
                bool retry;
                Exception completeException = null;
 
                try
                { 
                    retry = this.CompleteInput(result); 
                }
#pragma warning suppress 56500 // covered by FxCOP 
                catch (Exception e)
                {
                    if (DiagnosticUtility.IsFatal(e))
                    { 
                        throw;
                    } 
 
                    if (!this.binder.HandleException(e, this.maskingMode, this.autoAborted))
                    { 
                        completeException = e;
                        retry = false;
                    }
                    else 
                    {
                        retry = true; 
                    } 
                }
 
                if (retry)
                {
                    this.StartOnNonUserThread();
                } 
                else
                { 
                    this.Complete(this.isSynchronous, completeException); 
                }
            } 

            static void OnInputCompleteStatic(IAsyncResult result)
            {
                if (!result.CompletedSynchronously) 
                {
                    InputAsyncResult inputResult = 
                        (InputAsyncResult)result.AsyncState; 
                    inputResult.OnInputComplete(result);
                } 
            }

            void OnTryGetChannelComplete(IAsyncResult result)
            { 
                this.isSynchronous = false;
                bool retry = false; 
                bool complete = false; 
                Exception completeException = null;
 
                try
                {
                    retry = this.CompleteTryGetChannel(result, out complete);
                } 
#pragma warning suppress 56500 // covered by FxCOP
                catch (Exception e) 
                { 
                    if (DiagnosticUtility.IsFatal(e))
                    { 
                        throw;
                    }

                    if (!this.binder.HandleException(e, this.maskingMode, this.autoAborted)) 
                    {
                        completeException = e; 
                        retry = false; 
                    }
                    else 
                    {
                        retry = true;
                    }
                } 

                // Can't complete AND retry. 
                if (complete && retry) 
                {
                    DiagnosticUtility.DebugAssert("The derived class' implementation of CompleteTryGetChannel() cannot indicate that the asynchronous operation should complete and retry."); 
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false);
                }

                if (retry) 
                {
                    this.StartOnNonUserThread(); 
                } 
                else if (complete || completeException != null)
                { 
                    this.Complete(this.isSynchronous, completeException);
                }
            }
 
            static void OnTryGetChannelCompleteStatic(IAsyncResult result)
            { 
                if (!result.CompletedSynchronously) 
                {
                    InputAsyncResult inputResult = 
                        (InputAsyncResult)result.AsyncState;
                    inputResult.OnTryGetChannelComplete(result);
                }
            } 

            protected bool Start() 
            { 
                while (true)
                { 
                    bool retry = false;
                    bool complete = false;

                    this.autoAborted = false; 

                    try 
                    { 
                        IAsyncResult result = this.binder.synchronizer.BeginTryGetChannelForInput(
                            canGetChannel, this.timeoutHelper.RemainingTime(), 
                            onTryGetChannelComplete, this);

                        if (result.CompletedSynchronously)
                        { 
                            retry = this.CompleteTryGetChannel(result, out complete);
                        } 
                    } 
                    catch (Exception e)
                    { 
                        if (DiagnosticUtility.IsFatal(e))
                        {
                            throw;
                        } 

                        if (!this.binder.HandleException(e, this.maskingMode, this.autoAborted)) 
                        { 
                            throw;
                        } 
                        else
                        {
                            retry = true;
                        } 
                    }
 
                    // Can't complete AND retry. 
                    if (complete && retry)
                    { 
                        DiagnosticUtility.DebugAssert("The derived class' implementation of CompleteTryGetChannel() cannot indicate that the asynchronous operation should complete and retry.");
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false);
                    }
 
                    if (!retry)
                    { 
                        return complete; 
                    }
                } 
            }

            void StartOnNonUserThread()
            { 
                bool complete = false;
                Exception completeException = null; 
 
                try
                { 
                    complete = this.Start();
                }
#pragma warning suppress 56500 // covered by FxCOP
                catch (Exception e) 
                {
                    if (DiagnosticUtility.IsFatal(e)) 
                        throw; 

                    completeException = e; 
                }

                if (complete || completeException != null)
                    this.Complete(false, completeException); 
            }
        } 
 
        sealed class MessageRequestContext : BinderRequestContext
        { 
            public MessageRequestContext(ReliableChannelBinder binder, Message message)
                : base(binder, message)
            {
            } 

            protected override void OnAbort() 
            { 
            }
 
            protected override void OnClose(TimeSpan timeout)
            {
            }
 
            protected override IAsyncResult OnBeginReply(Message message, TimeSpan timeout, AsyncCallback callback, object state)
            { 
                return new ReplyAsyncResult(this, message, timeout, callback, state); 
            }
 
            protected override void OnEndReply(IAsyncResult result)
            {
                ReplyAsyncResult.End(result);
            } 

            protected override void OnReply(Message message, TimeSpan timeout) 
            { 
                if (message != null)
                { 
                    this.Binder.Send(message, timeout, this.MaskingMode);
                }
            }
 
            class ReplyAsyncResult : AsyncResult
            { 
                static AsyncCallback onSend; 
                MessageRequestContext context;
 
                public ReplyAsyncResult(MessageRequestContext context, Message message, TimeSpan timeout, AsyncCallback callback, object state)
                    : base(callback, state)
                {
                    if (message != null) 
                    {
                        if (onSend == null) 
                        { 
                            onSend = DiagnosticUtility.ThunkAsyncCallback(new AsyncCallback(OnSend));
                        } 
                        this.context = context;
                        IAsyncResult result = context.Binder.BeginSend(message, timeout, context.MaskingMode, onSend, this);
                        if (!result.CompletedSynchronously)
                        { 
                            return;
                        } 
                        context.Binder.EndSend(result); 
                    }
 
                    base.Complete(true);
                }

                public static void End(IAsyncResult result) 
                {
                    AsyncResult.End(result); 
                } 

                static void OnSend(IAsyncResult result) 
                {
                    if (result.CompletedSynchronously)
                    {
                        return; 
                    }
 
                    Exception completionException = null; 
                    ReplyAsyncResult thisPtr = (ReplyAsyncResult)result.AsyncState;
                    try 
                    {
                        thisPtr.context.Binder.EndSend(result);
                    }
#pragma warning suppress 56500 // covered by FxCOP 
                    catch (Exception exception)
                    { 
                        if (DiagnosticUtility.IsFatal(exception)) 
                        {
                            throw; 
                        }
                        completionException = exception;
                    }
 
                    thisPtr.Complete(false, completionException);
                } 
            } 
        }
 
        protected abstract class OutputAsyncResult : AsyncResult
            where TBinder : ReliableChannelBinder
        {
            bool autoAborted; 
            TBinder binder;
            TChannel channel; 
            bool hasChannel = false; 
            MaskingMode maskingMode;
            Message message; 
            static AsyncCallback onTryGetChannelComplete = DiagnosticUtility.ThunkAsyncCallback(new AsyncCallback(OnTryGetChannelCompleteStatic));
            static AsyncCallback onOutputComplete = DiagnosticUtility.ThunkAsyncCallback(new AsyncCallback(OnOutputCompleteStatic));
            TimeSpan timeout;
            TimeoutHelper timeoutHelper; 

            public OutputAsyncResult(TBinder binder, AsyncCallback callback, object state) 
                : base(callback, state) 
            {
                this.binder = binder; 
            }

            public MaskingMode MaskingMode
            { 
                get
                { 
                    return this.maskingMode; 
                }
            } 

            protected abstract IAsyncResult BeginOutput(TBinder binder, TChannel channel,
                Message message, TimeSpan timeout, MaskingMode maskingMode, AsyncCallback callback,
                object state); 

            void Cleanup() 
            { 
                if (this.hasChannel)
                { 
                    this.autoAborted = this.binder.Synchronizer.Aborting;
                    this.binder.synchronizer.ReturnChannel();
                }
            } 

            bool CompleteOutput(IAsyncResult result) 
            { 
                this.EndOutput(this.binder, this.channel, this.maskingMode, result);
                this.Cleanup(); 
                return true;
            }

            bool CompleteTryGetChannel(IAsyncResult result) 
            {
                bool timedOut = !this.binder.synchronizer.EndTryGetChannel(result, 
                    out this.channel); 

                if (timedOut || (this.channel == null)) 
                {
                    this.Cleanup();

                    if (timedOut && !ReliableChannelBinderHelper.MaskHandled(maskingMode)) 
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new TimeoutException(this.GetTimeoutString(this.timeout))); 
                    } 

                    return true; 
                }

                this.hasChannel = true;
 
                result = this.BeginOutput(this.binder, this.channel, this.message,
                    this.timeoutHelper.RemainingTime(), this.maskingMode, onOutputComplete, 
                    this); 

                if (result.CompletedSynchronously) 
                {
                    return this.CompleteOutput(result);
                }
                else 
                {
                    return false; 
                } 
            }
 
            protected abstract void EndOutput(TBinder binder, TChannel channel,
                MaskingMode maskingMode, IAsyncResult result);

            protected abstract string GetTimeoutString(TimeSpan timeout); 

            void OnOutputComplete(IAsyncResult result) 
            { 
                if (!result.CompletedSynchronously)
                { 
                    bool complete = false;
                    Exception completeException = null;

                    try 
                    {
                        complete = this.CompleteOutput(result); 
                    } 
#pragma warning suppress 56500 // covered by FxCOP
                    catch (Exception e) 
                    {
                        if (DiagnosticUtility.IsFatal(e))
                        {
                            throw; 
                        }
 
                        this.Cleanup(); 
                        complete = true;
                        if (!this.binder.HandleException(e, this.maskingMode, this.autoAborted)) 
                        {
                            completeException = e;
                        }
                    } 

                    if (complete) 
                    { 
                        this.Complete(false, completeException);
                    } 
                }
            }

            static void OnOutputCompleteStatic(IAsyncResult result) 
            {
                OutputAsyncResult outputResult = 
                    (OutputAsyncResult)result.AsyncState; 

                outputResult.OnOutputComplete(result); 
            }

            void OnTryGetChannelComplete(IAsyncResult result)
            { 
                if (!result.CompletedSynchronously)
                { 
                    bool complete = false; 
                    Exception completeException = null;
 
                    try
                    {
                        complete = this.CompleteTryGetChannel(result);
                    } 
#pragma warning suppress 56500 // covered by FxCOP
                    catch (Exception e) 
                    { 
                        if (DiagnosticUtility.IsFatal(e))
                        { 
                            throw;
                        }

                        this.Cleanup(); 
                        complete = true;
                        if (!this.binder.HandleException(e, this.maskingMode, this.autoAborted)) 
                        { 
                            completeException = e;
                        } 
                    }

                    if (complete)
                    { 
                        this.Complete(false, completeException);
                    } 
                } 
            }
 
            static void OnTryGetChannelCompleteStatic(IAsyncResult result)
            {
                OutputAsyncResult outputResult =
                    (OutputAsyncResult)result.AsyncState; 

                outputResult.OnTryGetChannelComplete(result); 
            } 

            public void Start(Message message, TimeSpan timeout, MaskingMode maskingMode) 
            {
                if (!this.binder.ValidateOutputOperation(message, timeout, maskingMode))
                {
                    this.Complete(true); 
                    return;
                } 
 
                this.message = message;
                this.timeout = timeout; 
                this.timeoutHelper = new TimeoutHelper(timeout);
                this.maskingMode = maskingMode;

                bool complete = false; 

                try 
                { 
                    IAsyncResult result = this.binder.synchronizer.BeginTryGetChannelForOutput(
                        timeoutHelper.RemainingTime(), this.maskingMode, onTryGetChannelComplete, this); 

                    if (result.CompletedSynchronously)
                    {
                        complete = this.CompleteTryGetChannel(result); 
                    }
                } 
                catch (Exception e) 
                {
                    if (DiagnosticUtility.IsFatal(e)) 
                    {
                        throw;
                    }
 
                    this.Cleanup();
                    if (this.binder.HandleException(e, this.maskingMode, this.autoAborted)) 
                    { 
                        complete = true;
                    } 
                    else
                    {
                        throw;
                    } 
                }
 
                if (complete) 
                {
                    this.Complete(true); 
                }
            }
        }
 
        sealed class RequestRequestContext : BinderRequestContext
        { 
            RequestContext innerContext; 

            public RequestRequestContext(ReliableChannelBinder binder, 
                RequestContext innerContext, Message message)
                : base(binder, message)
            {
                if ((binder.defaultMaskingMode != MaskingMode.All) && !binder.TolerateFaults) 
                {
                    DiagnosticUtility.DebugAssert("This request context is designed to catch exceptions. Thus it cannot be used if the caller expects no exception handling."); 
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); 
                }
 
                if (innerContext == null)
                {
                    DiagnosticUtility.DebugAssert("Argument innerContext cannot be null.");
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); 
                }
 
                this.innerContext = innerContext; 
            }
 
            protected override void OnAbort()
            {
                this.innerContext.Abort();
            } 

            protected override IAsyncResult OnBeginReply(Message message, TimeSpan timeout, 
                AsyncCallback callback, object state) 
            {
                try 
                {
                    if (message != null)
                        this.Binder.AddOutputHeaders(message);
                    return this.innerContext.BeginReply(message, timeout, callback, state); 
                }
                catch (ObjectDisposedException) { } 
                catch (Exception e) 
                {
                    if (DiagnosticUtility.IsFatal(e)) 
                    {
                        throw;
                    }
 
                    if (!this.Binder.HandleException(e, this.MaskingMode))
                    { 
                        throw; 
                    }
 
                    this.innerContext.Abort();
                }

                return new BinderCompletedAsyncResult(callback, state); 
            }
 
            protected override void OnClose(TimeSpan timeout) 
            {
                try 
                {
                    this.innerContext.Close(timeout);
                }
                catch (ObjectDisposedException) { } 
                catch (Exception e)
                { 
                    if (DiagnosticUtility.IsFatal(e)) 
                    {
                        throw; 
                    }

                    if (!this.Binder.HandleException(e, this.MaskingMode))
                    { 
                        throw;
                    } 
 
                    this.innerContext.Abort();
                } 
            }

            protected override void OnEndReply(IAsyncResult result)
            { 
                BinderCompletedAsyncResult completedResult = result as BinderCompletedAsyncResult;
                if (completedResult != null) 
                { 
                    completedResult.End();
                    return; 
                }

                try
                { 
                    this.innerContext.EndReply(result);
                } 
                catch (ObjectDisposedException) { } 
                catch (Exception e)
                { 
                    if (DiagnosticUtility.IsFatal(e))
                    {
                        throw;
                    } 

                    if (!this.Binder.HandleException(e, this.MaskingMode)) 
                    { 
                        throw;
                    } 

                    this.innerContext.Abort();
                }
            } 

            protected override void OnReply(Message message, TimeSpan timeout) 
            { 
                try
                { 
                    if (message != null)
                        this.Binder.AddOutputHeaders(message);
                    this.innerContext.Reply(message, timeout);
                } 
                catch (ObjectDisposedException) { }
                catch (Exception e) 
                { 
                    if (DiagnosticUtility.IsFatal(e))
                    { 
                        throw;
                    }

                    if (!this.Binder.HandleException(e, this.MaskingMode)) 
                    {
                        throw; 
                    } 

                    this.innerContext.Abort(); 
                }
            }
        }
 
        sealed class SendAsyncResult : OutputAsyncResult>
        { 
            public SendAsyncResult(ReliableChannelBinder binder, AsyncCallback callback, 
                object state)
                : base(binder, callback, state) 
            {
            }

            protected override IAsyncResult BeginOutput(ReliableChannelBinder binder, 
                TChannel channel, Message message, TimeSpan timeout, MaskingMode maskingMode,
                AsyncCallback callback, object state) 
            { 
                binder.AddOutputHeaders(message);
                return binder.OnBeginSend(channel, message, timeout, callback, state); 
            }

            public static void End(IAsyncResult result)
            { 
                AsyncResult.End(result);
            } 
 
            protected override void EndOutput(ReliableChannelBinder binder,
                TChannel channel, MaskingMode maskingMode, IAsyncResult result) 
            {
                binder.OnEndSend(channel, result);
            }
 
            protected override string GetTimeoutString(TimeSpan timeout)
            { 
                return SR.GetString(SR.TimeoutOnSend, timeout); 
            }
        } 

        sealed class TryReceiveAsyncResult : InputAsyncResult>
        {
            RequestContext requestContext; 

            public TryReceiveAsyncResult(ReliableChannelBinder binder, TimeSpan timeout, 
                MaskingMode maskingMode, AsyncCallback callback, object state) 
                : base(binder, binder.CanGetChannelForReceive, timeout, maskingMode, callback, state)
            { 
                if (this.Start())
                    this.Complete(true);
            }
 
            protected override IAsyncResult BeginInput(ReliableChannelBinder binder,
                TChannel channel, TimeSpan timeout, AsyncCallback callback, object state) 
            { 
                return binder.OnBeginTryReceive(channel, timeout, callback, state);
            } 

            public bool End(out RequestContext requestContext)
            {
                requestContext = this.requestContext; 
                return this.End();
            } 
 
            protected override bool EndInput(ReliableChannelBinder binder,
                TChannel channel, IAsyncResult result, out bool complete) 
            {
                bool success = binder.OnEndTryReceive(channel, result, out this.requestContext);

                // timed out || got message, complete immediately 
                complete = !success || (this.requestContext != null);
 
                if (!complete) 
                {
                    // the underlying channel closed or faulted 
                    binder.synchronizer.OnReadEof();
                }

                return success; 
            }
        } 
    } 

    static class ReliableChannelBinderHelper 
    {
        internal static IAsyncResult BeginCloseDuplexSessionChannel(
            ReliableChannelBinder binder, IDuplexSessionChannel channel,
            TimeSpan timeout, AsyncCallback callback, object state) 
        {
            return new CloseDuplexSessionChannelAsyncResult(binder, channel, timeout, callback, 
                state); 
        }
 
        internal static IAsyncResult BeginCloseReplySessionChannel(
            ReliableChannelBinder binder, IReplySessionChannel channel,
            TimeSpan timeout, AsyncCallback callback, object state)
        { 
            return new CloseReplySessionChannelAsyncResult(binder, channel, timeout, callback,
                state); 
        } 

        internal static void CloseDuplexSessionChannel( 
            ReliableChannelBinder binder, IDuplexSessionChannel channel,
            TimeSpan timeout)
        {
            TimeoutHelper timeoutHelper = new TimeoutHelper(timeout); 

            channel.Session.CloseOutputSession(timeoutHelper.RemainingTime()); 
            binder.WaitForPendingOperations(timeoutHelper.RemainingTime()); 

            TimeSpan iterationTimeout = timeoutHelper.RemainingTime(); 
            bool lastIteration = (iterationTimeout == TimeSpan.Zero);

            while (true)
            { 
                Message message = null;
                bool receiveThrowing = true; 
 
                try
                { 
                    bool success = channel.TryReceive(iterationTimeout, out message);

                    receiveThrowing = false;
                    if (success && message == null) 
                    {
                        channel.Close(timeoutHelper.RemainingTime()); 
                        return; 
                    }
                } 
                catch (Exception e)
                {
                    if (DiagnosticUtility.IsFatal(e))
                        throw; 

                    if (receiveThrowing) 
                    { 
                        if (!MaskHandled(binder.DefaultMaskingMode) || !binder.IsHandleable(e))
                            throw; 

                        receiveThrowing = false;
                    }
                    else 
                    {
                        throw; 
                    } 
                }
                finally 
                {
                    if (message != null)
                        message.Close();
 
                    if (receiveThrowing)
                        channel.Abort(); 
                } 

                if (lastIteration || channel.State != CommunicationState.Opened) 
                    break;

                iterationTimeout = timeoutHelper.RemainingTime();
                lastIteration = (iterationTimeout == TimeSpan.Zero); 
            }
 
            channel.Abort(); 
        }
 
        internal static void CloseReplySessionChannel(
            ReliableChannelBinder binder, IReplySessionChannel channel,
            TimeSpan timeout)
        { 
            TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
 
            binder.WaitForPendingOperations(timeoutHelper.RemainingTime()); 

            TimeSpan iterationTimeout = timeoutHelper.RemainingTime(); 
            bool lastIteration = (iterationTimeout == TimeSpan.Zero);

            while (true)
            { 
                RequestContext context = null;
                bool receiveThrowing = true; 
 
                try
                { 
                    bool success = channel.TryReceiveRequest(iterationTimeout, out context);

                    receiveThrowing = false;
                    if (success && context == null) 
                    {
                        channel.Close(timeoutHelper.RemainingTime()); 
                        return; 
                    }
                } 
                catch (Exception e)
                {
                    if (DiagnosticUtility.IsFatal(e))
                        throw; 

                    if (receiveThrowing) 
                    { 
                        if (!MaskHandled(binder.DefaultMaskingMode) || !binder.IsHandleable(e))
                            throw; 

                        receiveThrowing = false;
                    }
                    else 
                    {
                        throw; 
                    } 
                }
                finally 
                {
                    if (context != null)
                    {
                        context.RequestMessage.Close(); 
                        context.Close();
                    } 
 
                    if (receiveThrowing)
                        channel.Abort(); 
                }

                if (lastIteration || channel.State != CommunicationState.Opened)
                    break; 

                iterationTimeout = timeoutHelper.RemainingTime(); 
                lastIteration = (iterationTimeout == TimeSpan.Zero); 
            }
 
            channel.Abort();
        }

        internal static void EndCloseDuplexSessionChannel(IDuplexSessionChannel channel, 
                IAsyncResult result)
        { 
            CloseDuplexSessionChannelAsyncResult.End(result); 
        }
 
        internal static void EndCloseReplySessionChannel(IReplySessionChannel channel,
                IAsyncResult result)
        {
            CloseReplySessionChannelAsyncResult.End(result); 
        }
 
        internal static bool MaskHandled(MaskingMode maskingMode) 
        {
            return (maskingMode & MaskingMode.Handled) == MaskingMode.Handled; 
        }

        internal static bool MaskUnhandled(MaskingMode maskingMode)
        { 
            return (maskingMode & MaskingMode.Unhandled) == MaskingMode.Unhandled;
        } 
 
        abstract class CloseInputSessionChannelAsyncResult : AsyncResult
            where TChannel : class, IChannel 
            where TItem : class
        {
            static AsyncCallback onChannelCloseCompleteStatic =
                DiagnosticUtility.ThunkAsyncCallback( 
                new AsyncCallback(OnChannelCloseCompleteStatic));
            static AsyncCallback onInputCompleteStatic = 
                DiagnosticUtility.ThunkAsyncCallback(new AsyncCallback(OnInputCompleteStatic)); 
            static AsyncCallback onWaitForPendingOperationsCompleteStatic =
                DiagnosticUtility.ThunkAsyncCallback( 
                new AsyncCallback(OnWaitForPendingOperationsCompleteStatic));
            ReliableChannelBinder binder;
            TChannel channel;
            bool lastReceive; 
            TimeoutHelper timeoutHelper;
 
            protected CloseInputSessionChannelAsyncResult( 
                ReliableChannelBinder binder, TChannel channel,
                TimeSpan timeout, AsyncCallback callback, object state) 
                : base(callback, state)
            {
                this.binder = binder;
                this.channel = channel; 
                this.timeoutHelper = new TimeoutHelper(timeout);
            } 
 
            protected TChannel Channel
            { 
                get
                {
                    return this.channel;
                } 
            }
 
            protected TimeSpan RemainingTime 
            {
                get 
                {
                    return this.timeoutHelper.RemainingTime();
                }
            } 

            protected bool Begin() 
            { 
                bool complete = false;
                IAsyncResult result = this.binder.BeginWaitForPendingOperations( 
                    this.RemainingTime, onWaitForPendingOperationsCompleteStatic,
                    this);

                if (result.CompletedSynchronously) 
                    complete = this.HandleWaitForPendingOperationsComplete(result);
 
                return complete; 
            }
 
            protected abstract IAsyncResult BeginTryInput(TimeSpan timeout, AsyncCallback callback,
                object state);

            protected abstract void DisposeItem(TItem item); 

            protected abstract bool EndTryInput(IAsyncResult result, out TItem item); 
 
            void HandleChannelCloseComplete(IAsyncResult result)
            { 
                this.channel.EndClose(result);
            }

            bool HandleInputComplete(IAsyncResult result, out bool gotEof) 
            {
                TItem item  = null; 
                bool endThrowing = true; 

                gotEof = false; 

                try
                {
                    bool success = false; 

                    success = this.EndTryInput(result, out item); 
                    endThrowing = false; 

                    if (!success || item != null) 
                    {
                        if (this.lastReceive || this.channel.State != CommunicationState.Opened)
                        {
                            this.channel.Abort(); 
                            return true;
                        } 
                        else 
                        {
                            return false; 
                        }
                    }

                    gotEof = true; 

                    result = this.channel.BeginClose(this.RemainingTime, 
                        onChannelCloseCompleteStatic, this); 
                    if (result.CompletedSynchronously)
                    { 
                        this.HandleChannelCloseComplete(result);
                        return true;
                    }
                    else 
                    {
                        return false; 
                    } 
                }
                catch (Exception e) 
                {
                    if (DiagnosticUtility.IsFatal(e))
                        throw;
 
                    if (endThrowing)
                    { 
                        if (!MaskHandled(binder.DefaultMaskingMode) || !binder.IsHandleable(e)) 
                            throw;
 
                        if (this.lastReceive || this.channel.State != CommunicationState.Opened)
                        {
                            this.channel.Abort();
                            return true; 
                        }
                        else 
                        { 
                            return false;
                        } 
                    }

                    throw;
                } 
                finally
                { 
                    if (item != null) 
                        this.DisposeItem(item);
 
                    if (endThrowing)
                        this.channel.Abort();
                }
            } 

            bool HandleWaitForPendingOperationsComplete(IAsyncResult result) 
            { 
                this.binder.EndWaitForPendingOperations(result);
                return this.WaitForEof(); 
            }

            static void OnChannelCloseCompleteStatic(IAsyncResult result)
            { 
                if (result.CompletedSynchronously)
                    return; 
 
                CloseInputSessionChannelAsyncResult closeResult =
                    (CloseInputSessionChannelAsyncResult)result.AsyncState; 

                Exception completeException = null;

                try 
                {
                    closeResult.HandleChannelCloseComplete(result); 
                } 
                catch (Exception e)
                { 
                    if (DiagnosticUtility.IsFatal(e))
                        throw;

                    completeException = e; 
                }
 
                closeResult.Complete(false, completeException); 
            }
 
            static void OnInputCompleteStatic(IAsyncResult result)
            {
                if (result.CompletedSynchronously)
                    return; 

                CloseInputSessionChannelAsyncResult closeResult = 
                    (CloseInputSessionChannelAsyncResult)result.AsyncState; 

                bool complete = false; 
                Exception completeException = null;

                try
                { 
                    bool gotEof;
 
                    complete = closeResult.HandleInputComplete(result, out gotEof); 
                    if (!complete && !gotEof)
                        complete = closeResult.WaitForEof(); 
                }
                catch (Exception e)
                {
                    if (DiagnosticUtility.IsFatal(e)) 
                        throw;
 
                    completeException = e; 
                }
 
                if (complete || completeException != null)
                    closeResult.Complete(false, completeException);
            }
 
            static void OnWaitForPendingOperationsCompleteStatic(IAsyncResult result)
            { 
                if (result.CompletedSynchronously) 
                    return;
 
                CloseInputSessionChannelAsyncResult closeResult =
                    (CloseInputSessionChannelAsyncResult)result.AsyncState;

                bool complete = false; 
                Exception completeException = null;
 
                try 
                {
                    complete = closeResult.HandleWaitForPendingOperationsComplete(result); 
                }
                catch (Exception e)
                {
                    if (DiagnosticUtility.IsFatal(e)) 
                        throw;
 
                    completeException = e; 
                }
 
                if (complete || completeException != null)
                    closeResult.Complete(false, completeException);
            }
 
            bool WaitForEof()
            { 
                TimeSpan iterationTimeout = this.RemainingTime; 
                this.lastReceive = (iterationTimeout == TimeSpan.Zero);
 
                while (true)
                {
                    IAsyncResult result = null;
 
                    try
                    { 
                        result = this.BeginTryInput(iterationTimeout, onInputCompleteStatic, this); 
                    }
                    catch (Exception e) 
                    {
                        if (DiagnosticUtility.IsFatal(e))
                            throw;
 
                        if (!MaskHandled(this.binder.DefaultMaskingMode) || !this.binder.IsHandleable(e))
                            throw; 
                    } 

                    if (result != null) 
                    {
                        if (result.CompletedSynchronously)
                        {
                            bool gotEof; 
                            bool complete = this.HandleInputComplete(result, out gotEof);
 
                            if (complete || gotEof) 
                                return complete;
                        } 
                        else
                            return false;
                    }
 
                    if (this.lastReceive || this.channel.State != CommunicationState.Opened)
                    { 
                        this.channel.Abort(); 
                        break;
                    } 

                    iterationTimeout = this.RemainingTime;
                    this.lastReceive = (iterationTimeout == TimeSpan.Zero);
                } 

                return true; 
            } 
        }
 
        sealed class CloseDuplexSessionChannelAsyncResult :
            CloseInputSessionChannelAsyncResult
        {
            static AsyncCallback onCloseOutputSessionCompleteStatic = 
                DiagnosticUtility.ThunkAsyncCallback(
                new AsyncCallback(OnCloseOutputSessionCompleteStatic)); 
 
            public CloseDuplexSessionChannelAsyncResult(
                ReliableChannelBinder binder, IDuplexSessionChannel channel, 
                TimeSpan timeout, AsyncCallback callback, object state)
                : base(binder, channel, timeout, callback, state)
            {
                bool complete = false; 

                IAsyncResult result = this.Channel.Session.BeginCloseOutputSession( 
                    this.RemainingTime, onCloseOutputSessionCompleteStatic, this); 

                if (result.CompletedSynchronously) 
                    complete = this.HandleCloseOutputSessionComplete(result);

                if (complete)
                    this.Complete(true); 
            }
 
            protected override IAsyncResult BeginTryInput(TimeSpan timeout, AsyncCallback callback, object state) 
            {
                return this.Channel.BeginTryReceive(timeout, callback, state); 
            }

            protected override void DisposeItem(Message item)
            { 
                item.Close();
            } 
 
            public static void End(IAsyncResult result)
            { 
                AsyncResult.End(result);
            }

            protected override bool EndTryInput(IAsyncResult result, out Message item) 
            {
                return this.Channel.EndTryReceive(result, out item); 
            } 

            bool HandleCloseOutputSessionComplete(IAsyncResult result) 
            {
                this.Channel.Session.EndCloseOutputSession(result);
                return this.Begin();
            } 

            static void OnCloseOutputSessionCompleteStatic(IAsyncResult result) 
            { 
                if (result.CompletedSynchronously)
                    return; 

                CloseDuplexSessionChannelAsyncResult closeResult =
                    (CloseDuplexSessionChannelAsyncResult)result.AsyncState;
 
                bool complete = false;
                Exception completeException = null; 
 
                try
                { 
                    complete = closeResult.HandleCloseOutputSessionComplete(result);
                }
                catch (Exception e)
                { 
                    if (DiagnosticUtility.IsFatal(e))
                        throw; 
 
                    completeException = e;
                } 

                if (complete || completeException != null)
                    closeResult.Complete(false, completeException);
            } 
        }
 
        sealed class CloseReplySessionChannelAsyncResult : 
            CloseInputSessionChannelAsyncResult
        { 
            public CloseReplySessionChannelAsyncResult(
                ReliableChannelBinder binder, IReplySessionChannel channel,
                TimeSpan timeout, AsyncCallback callback, object state)
                : base(binder, channel, timeout, callback, state) 
            {
                if (this.Begin()) 
                    this.Complete(true); 
            }
 
            protected override IAsyncResult BeginTryInput(TimeSpan timeout, AsyncCallback callback, object state)
            {
                return this.Channel.BeginTryReceiveRequest(timeout, callback, state);
            } 

            protected override void DisposeItem(RequestContext item) 
            { 
                item.RequestMessage.Close();
                item.Close(); 
            }

            public static void End(IAsyncResult result)
            { 
                AsyncResult.End(result);
            } 
 
            protected override bool EndTryInput(IAsyncResult result, out RequestContext item)
            { 
                return this.Channel.EndTryReceiveRequest(result, out item);
            }
        }
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.


                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK