File: System\ServiceModel\Channels\ContextChannelRequestContext.cs
Project: ndp\cdf\src\WCF\ServiceModel\System.ServiceModel.csproj (System.ServiceModel)
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//------------------------------------------------------------
 
namespace System.ServiceModel.Channels
{
    using System;
    using System.Runtime;
    using System.ServiceModel;
 
    class ContextChannelRequestContext : RequestContext
    {
        ContextProtocol contextProtocol;
        TimeSpan defaultSendTimeout;
        RequestContext innerContext;
 
        public ContextChannelRequestContext(RequestContext innerContext, ContextProtocol contextProtocol, TimeSpan defaultSendTimeout)
        {
            if (innerContext == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("innerContext");
            }
            if (contextProtocol == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("contextProtocol");
            }
 
            this.innerContext = innerContext;
            this.contextProtocol = contextProtocol;
            this.defaultSendTimeout = defaultSendTimeout;
        }
 
        public override Message RequestMessage
        {
            get { return this.innerContext.RequestMessage; }
        }
 
        public override void Abort()
        {
            this.innerContext.Abort();
        }
 
        public override IAsyncResult BeginReply(Message message, TimeSpan timeout, AsyncCallback callback, object state)
        {
            return new ReplyAsyncResult(message, this, timeout, callback, state);
        }
 
        public override IAsyncResult BeginReply(Message message, AsyncCallback callback, object state)
        {
            return this.BeginReply(message, this.defaultSendTimeout, callback, state);
        }
 
        public override void Close(TimeSpan timeout)
        {
            this.innerContext.Close(timeout);
        }
 
        public override void Close()
        {
            this.innerContext.Close();
        }
 
        public override void EndReply(IAsyncResult result)
        {
            ReplyAsyncResult.End(result);
        }
 
        public override void Reply(Message message, TimeSpan timeout)
        {
            TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
            Message replyMessage = message;
 
            if (message != null)
            {
                this.contextProtocol.OnOutgoingMessage(message, this);
 
                CorrelationCallbackMessageProperty callback;
                if (CorrelationCallbackMessageProperty.TryGet(message, out callback))
                {
                    ContextExchangeCorrelationHelper.AddOutgoingCorrelationCallbackData(callback, message, false);
 
                    if (callback.IsFullyDefined)
                    {
                        replyMessage = callback.FinalizeCorrelation(message, timeoutHelper.RemainingTime());
                        // we are done finalizing correlation, removing the messageproperty since we do not need it anymore
                        replyMessage.Properties.Remove(CorrelationCallbackMessageProperty.Name);
                    }
 
                }
            }
 
            try
            {
                this.innerContext.Reply(replyMessage, timeoutHelper.RemainingTime());
            }
            finally
            {
                if (message != null && !object.ReferenceEquals(message, replyMessage))
                {
                    replyMessage.Close();
                }
            }
        }
 
        public override void Reply(Message message)
        {
            this.Reply(message, this.defaultSendTimeout);
        }
 
        class ReplyAsyncResult : AsyncResult
        {
 
            static AsyncCallback onFinalizeCorrelation = Fx.ThunkCallback(new AsyncCallback(OnFinalizeCorrelationCompletedCallback));
            static AsyncCallback onReply = Fx.ThunkCallback(new AsyncCallback(OnReplyCompletedCallback));
            ContextChannelRequestContext context;
            CorrelationCallbackMessageProperty correlationCallback;
            Message message;
            Message replyMessage;
            TimeoutHelper timeoutHelper;
 
            public ReplyAsyncResult(Message message, ContextChannelRequestContext context, TimeSpan timeout, AsyncCallback callback, object state)
                : base(callback, state)
            {
                this.context = context;
                this.message = this.replyMessage = message;
                this.timeoutHelper = new TimeoutHelper(timeout);
                bool shouldReply = true;
 
                if (message != null)
                {
                    this.context.contextProtocol.OnOutgoingMessage(message, this.context);
 
                    if (CorrelationCallbackMessageProperty.TryGet(message, out this.correlationCallback))
                    {
                        ContextExchangeCorrelationHelper.AddOutgoingCorrelationCallbackData(this.correlationCallback, message, false);
 
                        if (this.correlationCallback.IsFullyDefined)
                        {
                            IAsyncResult result = correlationCallback.BeginFinalizeCorrelation(this.message, this.timeoutHelper.RemainingTime(), onFinalizeCorrelation, this);
                            if (result.CompletedSynchronously)
                            {
                                if (OnFinalizeCorrelationCompleted(result))
                                {
                                    base.Complete(true);
                                }
                            }
 
                            shouldReply = false;
                        }
                    }
                }
 
                if (shouldReply)
                {
                    IAsyncResult result = this.context.innerContext.BeginReply(this.message, this.timeoutHelper.RemainingTime(), onReply, this);
                    if (result.CompletedSynchronously)
                    {
                        OnReplyCompleted(result);
                        base.Complete(true);
                    }
                }
            }
 
            public static void End(IAsyncResult result)
            {
                AsyncResult.End<ReplyAsyncResult>(result);
            }
 
            static void OnFinalizeCorrelationCompletedCallback(IAsyncResult result)
            {
                if (result.CompletedSynchronously)
                {
                    return;
                }
 
                ReplyAsyncResult thisPtr = (ReplyAsyncResult)result.AsyncState;
 
                Exception completionException = null;
                bool completeSelf;
                try
                {
                    completeSelf = thisPtr.OnFinalizeCorrelationCompleted(result);
                }
                catch (Exception e)
                {
                    if (Fx.IsFatal(e))
                    {
                        throw;
                    }
 
                    completionException = e;
                    completeSelf = true;
                }
 
                if (completeSelf)
                {
                    thisPtr.Complete(false, completionException);
                }
            }
 
            static void OnReplyCompletedCallback(IAsyncResult result)
            {
                if (result.CompletedSynchronously)
                {
                    return;
                }
 
                ReplyAsyncResult thisPtr = (ReplyAsyncResult)result.AsyncState;
 
                Exception completionException = null;
                try
                {
                    thisPtr.OnReplyCompleted(result);
                }
                catch (Exception e)
                {
                    if (Fx.IsFatal(e))
                    {
                        throw;
                    }
 
                    completionException = e;
                }
 
                thisPtr.Complete(false, completionException);
            }
 
            bool OnFinalizeCorrelationCompleted(IAsyncResult result)
            {
                this.replyMessage = this.correlationCallback.EndFinalizeCorrelation(result);
 
                bool throwing = true;
                IAsyncResult replyResult;
                try
                {
                    replyResult = this.context.innerContext.BeginReply(this.replyMessage, this.timeoutHelper.RemainingTime(), onReply, this);
                    throwing = false;
                }
                finally
                {
                    if (throwing)
                    {
                        if (this.message != null && !object.ReferenceEquals(this.message, this.replyMessage))
                        {
                            this.replyMessage.Close();
                        }
                    }
                }
 
                if (replyResult.CompletedSynchronously)
                {
                    OnReplyCompleted(replyResult);
                    return true;
                }
 
                return false;
            }
 
            void OnReplyCompleted(IAsyncResult result)
            {
                try
                {
                    this.context.innerContext.EndReply(result);
                }
                finally
                {
                    if (this.message != null && !object.ReferenceEquals(this.message, this.replyMessage))
                    {
                        this.replyMessage.Close();
                    }
                }
            }
        }
    }
}