internal ImmutableDispatchRuntime(DispatchRuntime dispatch)
        {
            _authenticationBehavior = AuthenticationBehavior.TryCreate(dispatch);
            _authorizationBehavior  = AuthorizationBehavior.TryCreate(dispatch);
            _concurrency            = new ConcurrencyBehavior(dispatch);
            _error        = new ErrorBehavior(dispatch.ChannelDispatcher);
            _enableFaults = dispatch.EnableFaults;
            _inputSessionShutdownHandlers = EmptyArray <IInputSessionShutdown> .ToArray(dispatch.InputSessionShutdownHandlers);

            InstanceBehavior   = new InstanceBehavior(dispatch, this);
            _isOnServer        = dispatch.IsOnServer;
            _manualAddressing  = dispatch.ManualAddressing;
            _messageInspectors = EmptyArray <IDispatchMessageInspector> .ToArray(dispatch.MessageInspectors);

            _securityImpersonation = SecurityImpersonationBehavior.CreateIfNecessary(dispatch);
            RequireClaimsPrincipalOnOperationContext = dispatch.RequireClaimsPrincipalOnOperationContext;
            _impersonateOnSerializingReply           = dispatch.ImpersonateOnSerializingReply;
            _terminate             = TerminatingOperationBehavior.CreateIfNecessary(dispatch);
            _thread                = new ThreadBehavior(dispatch);
            ValidateMustUnderstand = dispatch.ValidateMustUnderstand;
            ParameterInspectorCorrelationOffset = (dispatch.MessageInspectors.Count +
                                                   dispatch.MaxCallContextInitializers);
            _correlationCount = ParameterInspectorCorrelationOffset + dispatch.MaxParameterInspectors;

            DispatchOperationRuntime unhandled = new DispatchOperationRuntime(dispatch.UnhandledDispatchOperation, this);

            if (dispatch.OperationSelector == null)
            {
                ActionDemuxer demuxer = new ActionDemuxer();
                for (int i = 0; i < dispatch.Operations.Count; i++)
                {
                    DispatchOperation        operation        = dispatch.Operations[i];
                    DispatchOperationRuntime operationRuntime = new DispatchOperationRuntime(operation, this);
                    demuxer.Add(operation.Action, operationRuntime);
                }

                demuxer.SetUnhandled(unhandled);
                _demuxer = demuxer;
            }
            else
            {
                CustomDemuxer demuxer = new CustomDemuxer(dispatch.OperationSelector);
                for (int i = 0; i < dispatch.Operations.Count; i++)
                {
                    DispatchOperation        operation        = dispatch.Operations[i];
                    DispatchOperationRuntime operationRuntime = new DispatchOperationRuntime(operation, this);
                    demuxer.Add(operation.Name, operationRuntime);
                }

                demuxer.SetUnhandled(unhandled);
                _demuxer = demuxer;
            }

            _processMessageNonCleanupError = new MessageRpcErrorHandler(ProcessMessageNonCleanupError);
            _processMessageCleanupError    = new MessageRpcErrorHandler(ProcessMessageCleanupError);
        }
Exemplo n.º 2
0
        internal InstanceBehavior(DispatchRuntime dispatch, ImmutableDispatchRuntime immutableRuntime)
        {
            this.immutableRuntime = immutableRuntime;
            initializers          = EmptyArray <IInstanceContextInitializer> .ToArray(dispatch.InstanceContextInitializers);

            provider  = dispatch.InstanceProvider;
            singleton = dispatch.SingletonInstanceContext;
            //    this.transactionAutoCompleteOnSessionClose = dispatch.TransactionAutoCompleteOnSessionClose;
            //    this.releaseServiceInstanceOnTransactionComplete = dispatch.ReleaseServiceInstanceOnTransactionComplete;
            isSynchronized          = (dispatch.ConcurrencyMode != ConcurrencyMode.Multiple);
            instanceContextProvider = dispatch.InstanceContextProvider;

            if (provider == null)
            {
                ConstructorInfo constructor = null;
                if (dispatch.Type != null)
                {
                    constructor = InstanceBehavior.GetConstructor(dispatch.Type);
                }

                if (singleton == null)
                {
                    if (dispatch.Type != null && (dispatch.Type.GetTypeInfo().IsAbstract || dispatch.Type.GetTypeInfo().IsInterface))
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.SFxServiceTypeNotCreatable));
                    }

                    if (constructor == null)
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.SFxNoDefaultConstructor));
                    }
                }

                if (constructor != null)
                {
                    if (singleton == null || !singleton.IsWellKnown)
                    {
                        InvokerUtil            util    = new InvokerUtil();
                        CreateInstanceDelegate creator = util.GenerateCreateInstanceDelegate(dispatch.Type, constructor);
                        provider = new InstanceProvider(creator);
                    }
                }
            }

            if (singleton != null)
            {
                singleton.Behavior = this;
            }
        }
Exemplo n.º 3
0
        //bool didTraceProcessMessage1 = false;
        //bool didTraceProcessMessage2 = false;
        //bool didTraceProcessMessage3 = false;
        //bool didTraceProcessMessage31 = false;
        //bool didTraceProcessMessage4 = false;
        //bool didTraceProcessMessage41 = false;

        internal ImmutableDispatchRuntime(DispatchRuntime dispatch)
        {
            //this.authenticationBehavior = AuthenticationBehavior.TryCreate(dispatch);
            //this.authorizationBehavior = AuthorizationBehavior.TryCreate(dispatch);
            concurrency  = new ConcurrencyBehavior(dispatch);
            error        = new ErrorBehavior(dispatch.ChannelDispatcher);
            enableFaults = dispatch.EnableFaults;
            inputSessionShutdownHandlers = EmptyArray <IInputSessionShutdown> .ToArray(dispatch.InputSessionShutdownHandlers);

            instance          = new InstanceBehavior(dispatch, this);
            isOnServer        = dispatch.IsOnServer;
            manualAddressing  = dispatch.ManualAddressing;
            messageInspectors = EmptyArray <IDispatchMessageInspector> .ToArray(dispatch.MessageInspectors);

            //this.requestReplyCorrelator = new RequestReplyCorrelator();
            //this.securityImpersonation = SecurityImpersonationBehavior.CreateIfNecessary(dispatch);
            //this.RequireClaimsPrincipalOnOperationContext = dispatch.RequireClaimsPrincipalOnOperationContext;
            //this.impersonateOnSerializingReply = dispatch.ImpersonateOnSerializingReply;
            terminate = TerminatingOperationBehavior.CreateIfNecessary(dispatch);
            thread    = new ThreadBehavior(dispatch);
            ValidateMustUnderstand = dispatch.ValidateMustUnderstand;
            //this.ignoreTransactionFlow = dispatch.IgnoreTransactionMessageProperty;
            //this.transaction = TransactionBehavior.CreateIfNeeded(dispatch);
            //sendAsynchronously = dispatch.ChannelDispatcher.SendAsynchronously;
            ParameterInspectorCorrelationOffset = (dispatch.MessageInspectors.Count +
                                                   dispatch.MaxCallContextInitializers);
            correlationCount = ParameterInspectorCorrelationOffset + dispatch.MaxParameterInspectors;

            DispatchOperationRuntime unhandled = new DispatchOperationRuntime(dispatch.UnhandledDispatchOperation, this);

            if (dispatch.OperationSelector == null)
            {
                ActionDemuxer demuxer = new ActionDemuxer();
                for (int i = 0; i < dispatch.Operations.Count; i++)
                {
                    DispatchOperation        operation        = dispatch.Operations[i];
                    DispatchOperationRuntime operationRuntime = new DispatchOperationRuntime(operation, this);
                    demuxer.Add(operation.Action, operationRuntime);
                }

                demuxer.SetUnhandled(unhandled);
                this.demuxer = demuxer;
            }
            else
            {
                throw new PlatformNotSupportedException();
                //    CustomDemuxer demuxer = new CustomDemuxer(dispatch.OperationSelector);
                //    for (int i = 0; i < dispatch.Operations.Count; i++)
                //    {
                //        DispatchOperation operation = dispatch.Operations[i];
                //        DispatchOperationRuntime operationRuntime = new DispatchOperationRuntime(operation, this);
                //        demuxer.Add(operation.Name, operationRuntime);
                //    }

                //    demuxer.SetUnhandled(unhandled);
                //    this.demuxer = demuxer;
            }

            //processMessage1 = new MessageRpcProcessor(ProcessMessage1);
            //processMessage11 = new MessageRpcProcessor(ProcessMessage11);
            //processMessage2 = new MessageRpcProcessor(ProcessMessage2);
            //processMessage3 = new MessageRpcProcessor(ProcessMessage3);
            //processMessage31 = new MessageRpcProcessor(ProcessMessage31);
            //processMessage4 = new MessageRpcProcessor(ProcessMessage4);
            //processMessage41 = new MessageRpcProcessor(ProcessMessage41);
            //processMessage5 = new MessageRpcProcessor(ProcessMessage5);
            //processMessage6 = new MessageRpcProcessor(ProcessMessage6);
            //processMessage7 = new MessageRpcProcessor(ProcessMessage7);
            //processMessage8 = new MessageRpcProcessor(ProcessMessage8);
            //processMessage9 = new MessageRpcProcessor(ProcessMessage9);
            //processMessageCleanup = new MessageRpcProcessor(ProcessMessageCleanup);
            processMessageNonCleanupError = new MessageRpcErrorHandler(ProcessMessageNonCleanupError);
            processMessageCleanupError    = new MessageRpcErrorHandler(ProcessMessageCleanupError);
        }
        // Logic for knowing when to close stuff:
        //
        // ASSUMPTIONS:
        //   Closing a stream over a message also closes the message.
        //   Closing a message over a stream does not close the stream.
        //     (OperationStreamProvider.ReleaseStream is no-op)
        //
        // This is a table of what should be disposed in what cases.
        // The rows represent the type of parameter to the method and
        // whether we are disposing parameters or not.  The columns
        // are for the inputs vs. the outputs.  The cells contain the
        // values that need to be Disposed.  M^P means that exactly
        // one of the message and parameter needs to be disposed,
        // since they refer to the same object.
        //
        //                               Request           Reply
        //               Message   |     M or P      |     M or P
        //     Dispose   Stream    |     P           |     M and P
        //               Params    |     M and P     |     M and P
        //                         |                 |
        //               Message   |     none        |     none
        //   NoDispose   Stream    |     none        |     M
        //               Params    |     M           |     M
        //
        // By choosing to dispose the parameter in both of the "M or P"
        // cases, the logic needed to generate this table is:
        //
        // CloseRequestMessage = IsParams
        // CloseRequestParams  = rpc.Operation.DisposeParameters
        // CloseReplyMessage   = rpc.Operation.SerializeReply
        // CloseReplyParams    = rpc.Operation.DisposeParameters
        //
        // IsParams can be calculated based on whether the request
        // message was consumed after deserializing but before calling
        // the user.  This is stored as rpc.DidDeserializeRequestBody.
        //
        void ProcessMessageCleanup(MessageRpc rpc)
        {
            Fx.Assert(
                !object.ReferenceEquals(rpc.ErrorProcessor, _processMessageCleanupError),
                "ProcessMessageCleanup run twice on the same MessageRpc!");
            rpc.ErrorProcessor = _processMessageCleanupError;

            bool replyWasSent = false;

            if (rpc.CanSendReply)
            {
                replyWasSent = rpc.SuccessfullySendReply;
            }

            try
            {
                try
                {
                    if (rpc.DidDeserializeRequestBody)
                    {
                        rpc.Request.Close();
                    }
                }
                catch (Exception e)
                {
                    if (Fx.IsFatal(e))
                    {
                        throw;
                    }
                    _error.HandleError(e);
                }

                rpc.DisposeParameters(false); //Dispose all input/output/return parameters

                if (rpc.FaultInfo.IsConsideredUnhandled)
                {
                    if (!replyWasSent)
                    {
                        rpc.AbortRequestContext();
                        rpc.AbortChannel();
                    }
                    else
                    {
                        rpc.CloseRequestContext();
                        rpc.CloseChannel();
                    }
                    rpc.AbortInstanceContext();
                }
                else
                {
                    if (rpc.RequestContextThrewOnReply)
                    {
                        rpc.AbortRequestContext();
                    }
                    else
                    {
                        rpc.CloseRequestContext();
                    }
                }

                if ((rpc.Reply != null) && (rpc.Reply != rpc.ReturnParameter))
                {
                    try
                    {
                        rpc.Reply.Close();
                    }
                    catch (Exception e)
                    {
                        if (Fx.IsFatal(e))
                        {
                            throw;
                        }
                        _error.HandleError(e);
                    }
                }

                if ((rpc.FaultInfo.Fault != null) && (rpc.FaultInfo.Fault.State != MessageState.Closed))
                {
                    // maybe ProvideFault gave a Message, but then BeforeSendReply replaced it
                    // in that case, we need to close the one from ProvideFault
                    try
                    {
                        rpc.FaultInfo.Fault.Close();
                    }
                    catch (Exception e)
                    {
                        if (Fx.IsFatal(e))
                        {
                            throw;
                        }
                        _error.HandleError(e);
                    }
                }

                try
                {
                    rpc.OperationContext.FireOperationCompleted();
                }

                catch (Exception e)
                {
                    if (Fx.IsFatal(e))
                    {
                        throw;
                    }
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperCallback(e);
                }

                InstanceBehavior.AfterReply(ref rpc, _error);

                if (rpc.SuccessfullyLockedInstance)
                {
                    try
                    {
                        _concurrency.UnlockInstance(ref rpc);
                    }
                    catch (Exception e)
                    {
                        if (Fx.IsFatal(e))
                        {
                            throw;
                        }

                        Fx.Assert("Exceptions should be caught by callee");
                        rpc.InstanceContext.FaultInternal();
                        _error.HandleError(e);
                    }
                }

                if (_terminate != null)
                {
                    try
                    {
                        _terminate.AfterReply(ref rpc);
                    }
                    catch (Exception e)
                    {
                        if (Fx.IsFatal(e))
                        {
                            throw;
                        }
                        _error.HandleError(e);
                    }
                }

                if (rpc.SuccessfullyIncrementedActivity)
                {
                    try
                    {
                        rpc.Channel.DecrementActivity();
                    }
                    catch (Exception e)
                    {
                        if (Fx.IsFatal(e))
                        {
                            throw;
                        }
                        _error.HandleError(e);
                    }
                }
            }
            finally
            {
                // TODO: Add the code for the other half of InstanceContextServiceThrottle being acquired
                if (rpc.MessageRpcOwnsInstanceContextThrottle && rpc.channelHandler.InstanceContextServiceThrottle != null)
                {
                    rpc.channelHandler.InstanceContextServiceThrottle.DeactivateInstanceContext();
                }

                //if (rpc.Activity != null && DiagnosticUtility.ShouldUseActivity)
                //{
                //    rpc.Activity.Stop();
                //}
            }

            _error.HandleError(rpc);
        }
        internal async Task <MessageRpc> ProcessMessageAsync(MessageRpc rpc)
        {
            if (rpc.Operation.IsOneWay)
            {
                await rpc.RequestContext.ReplyAsync(null);

                rpc.OperationContext.RequestContext = null;
            }
            else
            {
                if (!rpc.Channel.IsReplyChannel &&
                    ((object)rpc.RequestID == null) &&
                    (rpc.Operation.Action != MessageHeaders.WildcardAction))
                {
                    CommunicationException error = new CommunicationException(SR.SFxOneWayMessageToTwoWayMethod0);
                    throw TraceUtility.ThrowHelperError(error, rpc.Request);
                }

                if (!_manualAddressing)
                {
                    EndpointAddress replyTo = rpc.ReplyToInfo.ReplyTo;
                    if (replyTo != null && replyTo.IsNone && rpc.Channel.IsReplyChannel)
                    {
                        CommunicationException error = new CommunicationException(SR.SFxRequestReplyNone);
                        throw TraceUtility.ThrowHelperError(error, rpc.Request);
                    }

                    if (_isOnServer)
                    {
                        EndpointAddress remoteAddress = rpc.Channel.RemoteAddress;
                        if ((remoteAddress != null) && !remoteAddress.IsAnonymous)
                        {
                            MessageHeaders headers   = rpc.Request.Headers;
                            Uri            remoteUri = remoteAddress.Uri;

                            if ((replyTo != null) && !replyTo.IsAnonymous && (remoteUri != replyTo.Uri))
                            {
                                string    text  = SR.Format(SR.SFxRequestHasInvalidReplyToOnServer, replyTo.Uri, remoteUri);
                                Exception error = new InvalidOperationException(text);
                                throw TraceUtility.ThrowHelperError(error, rpc.Request);
                            }

                            EndpointAddress faultTo = headers.FaultTo;
                            if ((faultTo != null) && !faultTo.IsAnonymous && (remoteUri != faultTo.Uri))
                            {
                                string    text  = SR.Format(SR.SFxRequestHasInvalidFaultToOnServer, faultTo.Uri, remoteUri);
                                Exception error = new InvalidOperationException(text);
                                throw TraceUtility.ThrowHelperError(error, rpc.Request);
                            }

                            if (rpc.RequestVersion.Addressing == AddressingVersion.WSAddressingAugust2004)
                            {
                                EndpointAddress from = headers.From;
                                if ((from != null) && !from.IsAnonymous && (remoteUri != from.Uri))
                                {
                                    string    text  = SR.Format(SR.SFxRequestHasInvalidFromOnServer, from.Uri, remoteUri);
                                    Exception error = new InvalidOperationException(text);
                                    throw TraceUtility.ThrowHelperError(error, rpc.Request);
                                }
                            }
                        }
                    }
                }
            }

            if (_concurrency.IsConcurrent(rpc))
            {
                rpc.Channel.IncrementActivity();
                rpc.SuccessfullyIncrementedActivity = true;
            }

            // TODO: Make authenticationBehavior Async
            if (_authenticationBehavior != null)
            {
                _authenticationBehavior.Authenticate(ref rpc);
            }

            // TODO: Make authorizationBehavior Async
            if (_authorizationBehavior != null)
            {
                _authorizationBehavior.Authorize(ref rpc);
            }

            await InstanceBehavior.EnsureInstanceContextAsync(rpc);

            TransferChannelFromPendingList(rpc);
            await AcquireDynamicInstanceContextAsync(rpc);

            AfterReceiveRequest(ref rpc);

            await _concurrency.LockInstanceAsync(rpc);

            rpc.SuccessfullyLockedInstance = true;

            try
            {
                // TaskHelpers has an extension method which enables awaitting a sync context to run continuation on it.
                await _thread.GetSyncContext(rpc);
            }
            catch (Exception e)
            {
                if (Fx.IsFatal(e))
                {
                    throw;
                }

                throw DiagnosticUtility.ExceptionUtility.ThrowHelperFatal(e.Message, e);
            }

            // This needs to happen after LockInstance--LockInstance guarantees
            // in-order delivery, so we can't receive the next message until we
            // have acquired the lock.
            //
            // This also needs to happen after BindThread based on the assumption
            // that running on UI thread should guarantee in-order delivery if
            // the SynchronizationContext is single threaded.
            if (_concurrency.IsConcurrent(rpc))
            {
                rpc.EnsureReceive();
                if (!rpc._processCallReturned)
                {
                    // To allow transport receive loop to get next request, the call to dispatch the current message needs to return.
                    // If all previous await's have completed synchronously, execution needs to be forced to continue on another thread.
                    // This code causes this method to continue on another thread and any calling receive pump (such as NetTcp) will
                    // use this thread to request the next message. It might be better to switch that so this thread continues on this
                    // thread and the caller has to run on a new thread.
                    await Task.Yield();
                }
            }

            InstanceBehavior.EnsureServiceInstance(rpc);

            try
            {
                SetActivityIdOnThread(rpc);
                rpc = await rpc.Operation.InvokeAsync(rpc);
            }
            catch
            {
                // This catch clause forces ClearCallContext to run prior to stackwalks exiting this frame.
                throw;
            }

            try
            {
                // Switch back to thread pool if we're using a non-default Sync Context. This only switches threads if needed.
                await TaskHelpers.EnsureDefaultTaskScheduler();
            }
            catch (Exception e)
            {
                if (Fx.IsFatal(e))
                {
                    throw;
                }

                throw DiagnosticUtility.ExceptionUtility.ThrowHelperFatal(e.Message, e);
            }

            await ProcessError(rpc);

            if (!_concurrency.IsConcurrent(rpc))
            {
                rpc.EnsureReceive();
            }

            return(rpc);
        }
Exemplo n.º 6
0
        internal async Task <MessageRpc> ProcessMessageAsync(MessageRpc rpc)
        {
            if (rpc.Operation.IsOneWay)
            {
                await rpc.RequestContext.ReplyAsync(null);

                rpc.OperationContext.RequestContext = null;
            }
            else
            {
                if (!rpc.Channel.IsReplyChannel &&
                    ((object)rpc.RequestID == null) &&
                    (rpc.Operation.Action != MessageHeaders.WildcardAction))
                {
                    CommunicationException error = new CommunicationException(SR.SFxOneWayMessageToTwoWayMethod0);
                    throw TraceUtility.ThrowHelperError(error, rpc.Request);
                }

                if (!_manualAddressing)
                {
                    EndpointAddress replyTo = rpc.ReplyToInfo.ReplyTo;
                    if (replyTo != null && replyTo.IsNone && rpc.Channel.IsReplyChannel)
                    {
                        CommunicationException error = new CommunicationException(SR.SFxRequestReplyNone);
                        throw TraceUtility.ThrowHelperError(error, rpc.Request);
                    }

                    if (_isOnServer)
                    {
                        EndpointAddress remoteAddress = rpc.Channel.RemoteAddress;
                        if ((remoteAddress != null) && !remoteAddress.IsAnonymous)
                        {
                            MessageHeaders headers   = rpc.Request.Headers;
                            Uri            remoteUri = remoteAddress.Uri;

                            if ((replyTo != null) && !replyTo.IsAnonymous && (remoteUri != replyTo.Uri))
                            {
                                string    text  = SR.Format(SR.SFxRequestHasInvalidReplyToOnServer, replyTo.Uri, remoteUri);
                                Exception error = new InvalidOperationException(text);
                                throw TraceUtility.ThrowHelperError(error, rpc.Request);
                            }

                            EndpointAddress faultTo = headers.FaultTo;
                            if ((faultTo != null) && !faultTo.IsAnonymous && (remoteUri != faultTo.Uri))
                            {
                                string    text  = SR.Format(SR.SFxRequestHasInvalidFaultToOnServer, faultTo.Uri, remoteUri);
                                Exception error = new InvalidOperationException(text);
                                throw TraceUtility.ThrowHelperError(error, rpc.Request);
                            }

                            if (rpc.RequestVersion.Addressing == AddressingVersion.WSAddressingAugust2004)
                            {
                                EndpointAddress from = headers.From;
                                if ((from != null) && !from.IsAnonymous && (remoteUri != from.Uri))
                                {
                                    string    text  = SR.Format(SR.SFxRequestHasInvalidFromOnServer, from.Uri, remoteUri);
                                    Exception error = new InvalidOperationException(text);
                                    throw TraceUtility.ThrowHelperError(error, rpc.Request);
                                }
                            }
                        }
                    }
                }
            }

            if (_concurrency.IsConcurrent(rpc))
            {
                rpc.Channel.IncrementActivity();
                rpc.SuccessfullyIncrementedActivity = true;
            }

            // TODO: Make authenticationBehavior Async
            if (_authenticationBehavior != null)
            {
                _authenticationBehavior.Authenticate(ref rpc);
            }

            // TODO: Make authorizationBehavior Async
            if (_authorizationBehavior != null)
            {
                _authorizationBehavior.Authorize(ref rpc);
            }

            await InstanceBehavior.EnsureInstanceContextAsync(rpc);

            TransferChannelFromPendingList(rpc);
            await AcquireDynamicInstanceContextAsync(rpc);

            AfterReceiveRequest(ref rpc);

            await _concurrency.LockInstanceAsync(rpc);

            rpc.SuccessfullyLockedInstance = true;

            try
            {
                // TaskHelpers has an extension method which enables awaitting a sync context to run continuation on it.
                await _thread.GetSyncContext(rpc);
            }
            catch (Exception e)
            {
                if (Fx.IsFatal(e))
                {
                    throw;
                }

                throw DiagnosticUtility.ExceptionUtility.ThrowHelperFatal(e.Message, e);
            }

            // This needs to happen after LockInstance--LockInstance guarantees
            // in-order delivery, so we can't receive the next message until we
            // have acquired the lock.
            //
            // This also needs to happen after BindThread based on the assumption
            // that running on UI thread should guarantee in-order delivery if
            // the SynchronizationContext is single threaded.
            if (_concurrency.IsConcurrent(rpc))
            {
                rpc.EnsureReceive();
                if (!rpc._processCallReturned)
                {
                    // To allow transport receive loop to get next request, the call to dispatch the current message needs to return.
                    // If all previous await's have completed synchronously, execution needs to be forced to continue on another thread.
                    // This code causes this method to continue on another thread and any calling receive pump (such as NetTcp) will
                    // use this thread to request the next message. It might be better to switch that so this thread continues on this
                    // thread and the caller has to run on a new thread.
                    await Task.Yield();
                }
            }

            InstanceBehavior.EnsureServiceInstance(rpc);

            try
            {
                SetActivityIdOnThread(rpc);
                rpc = await rpc.Operation.InvokeAsync(rpc);
            }
            catch
            {
                // This catch clause forces ClearCallContext to run prior to stackwalks exiting this frame.
                throw;
            }

            try
            {
                // Switch back to thread pool if we're using a non-default Sync Context. This only switches threads if needed.
                await TaskHelpers.EnsureDefaultTaskScheduler();
            }
            catch (Exception e)
            {
                if (Fx.IsFatal(e))
                {
                    throw;
                }

                throw DiagnosticUtility.ExceptionUtility.ThrowHelperFatal(e.Message, e);
            }

            try
            {
                _error.ProvideMessageFault(rpc);
            }
            catch (Exception e)
            {
                if (Fx.IsFatal(e))
                {
                    throw;
                }

                _error.HandleError(e);
            }

            PrepareReply(rpc);

            if (rpc.CanSendReply)
            {
                rpc.ReplyTimeoutHelper = new TimeoutHelper(rpc.Channel.OperationTimeout);
            }

            if (rpc.CanSendReply)
            {
                //if (rpc.Reply != null)
                //{
                //    TraceUtility.MessageFlowAtMessageSent(rpc.Reply, rpc.EventTraceActivity);
                //}

                rpc = await ReplyAsync(rpc);
            }

            // Logic for knowing when to close stuff:
            //
            // ASSUMPTIONS:
            //   Closing a stream over a message also closes the message.
            //   Closing a message over a stream does not close the stream.
            //     (OperationStreamProvider.ReleaseStream is no-op)
            //
            // This is a table of what should be disposed in what cases.
            // The rows represent the type of parameter to the method and
            // whether we are disposing parameters or not.  The columns
            // are for the inputs vs. the outputs.  The cells contain the
            // values that need to be Disposed.  M^P means that exactly
            // one of the message and parameter needs to be disposed,
            // since they refer to the same object.
            //
            //                               Request           Reply
            //               Message   |     M or P      |     M or P
            //     Dispose   Stream    |     P           |     M and P
            //               Params    |     M and P     |     M and P
            //                         |                 |
            //               Message   |     none        |     none
            //   NoDispose   Stream    |     none        |     M
            //               Params    |     M           |     M
            //
            // By choosing to dispose the parameter in both of the "M or P"
            // cases, the logic needed to generate this table is:
            //
            // CloseRequestMessage = IsParams
            // CloseRequestParams  = rpc.Operation.DisposeParameters
            // CloseReplyMessage   = rpc.Operation.SerializeReply
            // CloseReplyParams    = rpc.Operation.DisposeParameters
            //
            // IsParams can be calculated based on whether the request
            // message was consumed after deserializing but before calling
            // the user.  This is stored as rpc.DidDeserializeRequestBody.
            //
            Fx.Assert(
                !object.ReferenceEquals(rpc.ErrorProcessor, _processMessageCleanupError),
                "ProcessMessageCleanup run twice on the same MessageRpc!");
            rpc.ErrorProcessor = _processMessageCleanupError;

            bool replyWasSent = false;

            if (rpc.CanSendReply)
            {
                replyWasSent = rpc.SuccessfullySendReply;
            }

            try
            {
                try
                {
                    if (rpc.DidDeserializeRequestBody)
                    {
                        rpc.Request.Close();
                    }
                }
                catch (Exception e)
                {
                    if (Fx.IsFatal(e))
                    {
                        throw;
                    }
                    _error.HandleError(e);
                }

                rpc.DisposeParameters(false); //Dispose all input/output/return parameters

                if (rpc.FaultInfo.IsConsideredUnhandled)
                {
                    if (!replyWasSent)
                    {
                        rpc.AbortRequestContext();
                        rpc.AbortChannel();
                    }
                    else
                    {
                        rpc.CloseRequestContext();
                        rpc.CloseChannel();
                    }
                    rpc.AbortInstanceContext();
                }
                else
                {
                    if (rpc.RequestContextThrewOnReply)
                    {
                        rpc.AbortRequestContext();
                    }
                    else
                    {
                        rpc.CloseRequestContext();
                    }
                }

                if ((rpc.Reply != null) && (rpc.Reply != rpc.ReturnParameter))
                {
                    try
                    {
                        rpc.Reply.Close();
                    }
                    catch (Exception e)
                    {
                        if (Fx.IsFatal(e))
                        {
                            throw;
                        }
                        _error.HandleError(e);
                    }
                }

                if ((rpc.FaultInfo.Fault != null) && (rpc.FaultInfo.Fault.State != MessageState.Closed))
                {
                    // maybe ProvideFault gave a Message, but then BeforeSendReply replaced it
                    // in that case, we need to close the one from ProvideFault
                    try
                    {
                        rpc.FaultInfo.Fault.Close();
                    }
                    catch (Exception e)
                    {
                        if (Fx.IsFatal(e))
                        {
                            throw;
                        }
                        _error.HandleError(e);
                    }
                }

                try
                {
                    rpc.OperationContext.FireOperationCompleted();
                }

                catch (Exception e)
                {
                    if (Fx.IsFatal(e))
                    {
                        throw;
                    }
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperCallback(e);
                }

                InstanceBehavior.AfterReply(ref rpc, _error);

                if (rpc.SuccessfullyLockedInstance)
                {
                    try
                    {
                        _concurrency.UnlockInstance(ref rpc);
                    }
                    catch (Exception e)
                    {
                        if (Fx.IsFatal(e))
                        {
                            throw;
                        }

                        Fx.Assert("Exceptions should be caught by callee");
                        rpc.InstanceContext.FaultInternal();
                        _error.HandleError(e);
                    }
                }

                if (_terminate != null)
                {
                    try
                    {
                        _terminate.AfterReply(ref rpc);
                    }
                    catch (Exception e)
                    {
                        if (Fx.IsFatal(e))
                        {
                            throw;
                        }
                        _error.HandleError(e);
                    }
                }

                if (rpc.SuccessfullyIncrementedActivity)
                {
                    try
                    {
                        rpc.Channel.DecrementActivity();
                    }
                    catch (Exception e)
                    {
                        if (Fx.IsFatal(e))
                        {
                            throw;
                        }
                        _error.HandleError(e);
                    }
                }
            }
            finally
            {
                // TODO: Add the code for the other half of InstanceContextServiceThrottle being acquired
                if (rpc.MessageRpcOwnsInstanceContextThrottle && rpc.channelHandler.InstanceContextServiceThrottle != null)
                {
                    rpc.channelHandler.InstanceContextServiceThrottle.DeactivateInstanceContext();
                }

                //if (rpc.Activity != null && DiagnosticUtility.ShouldUseActivity)
                //{
                //    rpc.Activity.Stop();
                //}
            }

            _error.HandleError(rpc);

            if (!_concurrency.IsConcurrent(rpc))
            {
                rpc.EnsureReceive();
            }

            return(rpc);
        }