DispatchOperationRuntime.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 / Dispatcher / DispatchOperationRuntime.cs / 3 / DispatchOperationRuntime.cs

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

namespace System.ServiceModel.Dispatcher 
{
    using System; 
    using System.ServiceModel.Channels; 
    using System.ServiceModel;
    using System.Reflection; 
    using System.Security.Principal;
    using System.Web.Security;
    using System.Collections;
    using System.ServiceModel.Diagnostics; 
    using System.Globalization;
    using System.Security; 
    using System.Diagnostics; 

    class DispatchOperationRuntime 
    {
        static AsyncCallback invokeCallback = DiagnosticUtility.ThunkAsyncCallback(new AsyncCallback(DispatchOperationRuntime.InvokeCallback));
        readonly string action;
        readonly ICallContextInitializer[] callContextInitializers; 
        readonly IDispatchFaultFormatter faultFormatter;
        readonly IDispatchMessageFormatter formatter; 
        readonly ImpersonationOption impersonation; 
        readonly IParameterInspector[] inspectors;
        readonly IOperationInvoker invoker; 
        readonly bool isTerminating;
        readonly bool isSynchronous;
        readonly string name;
        readonly ImmutableDispatchRuntime parent; 
        readonly bool releaseInstanceAfterCall;
        readonly bool releaseInstanceBeforeCall; 
        readonly string replyAction; 
        readonly bool transactionAutoComplete;
        readonly bool transactionRequired; 
        readonly bool deserializeRequest;
        readonly bool serializeReply;
        readonly bool isOneWay;
        readonly bool disposeParameters; 

        internal DispatchOperationRuntime(DispatchOperation operation, ImmutableDispatchRuntime parent) 
        { 
            if (operation == null)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("operation");
            }
            if (parent == null)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("parent");
            } 
            if (operation.Invoker == null) 
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.RuntimeRequiresInvoker0))); 
            }

            this.disposeParameters = ((operation.AutoDisposeParameters) && (!operation.HasNoDisposableParameters));
            this.parent = parent; 
            this.callContextInitializers = EmptyArray.ToArray(operation.CallContextInitializers);
            this.inspectors = EmptyArray.ToArray(operation.ParameterInspectors); 
            this.faultFormatter = operation.FaultFormatter; 
            this.impersonation = operation.Impersonation;
            this.deserializeRequest = operation.DeserializeRequest; 
            this.serializeReply = operation.SerializeReply;
            this.formatter = operation.Formatter;
            this.invoker = operation.Invoker;
 
            try
            { 
                this.isSynchronous = operation.Invoker.IsSynchronous; 
            }
            catch (Exception e) 
            {
                if (DiagnosticUtility.IsFatal(e))
                {
                    throw; 
                }
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperCallback(e); 
            } 
            this.isTerminating = operation.IsTerminating;
            this.action = operation.Action; 
            this.name = operation.Name;
            this.releaseInstanceAfterCall = operation.ReleaseInstanceAfterCall;
            this.releaseInstanceBeforeCall = operation.ReleaseInstanceBeforeCall;
            this.replyAction = operation.ReplyAction; 
            this.isOneWay = operation.IsOneWay;
            this.transactionAutoComplete = operation.TransactionAutoComplete; 
            this.transactionRequired = operation.TransactionRequired; 

            if (this.formatter == null && (deserializeRequest || serializeReply)) 
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.DispatchRuntimeRequiresFormatter0, this.name)));
            }
 
            if ((operation.Parent.InstanceProvider == null) && (operation.Parent.Type != null))
            { 
                SyncMethodInvoker sync = this.invoker as SyncMethodInvoker; 
                if (sync != null)
                { 
                    this.ValidateInstanceType(operation.Parent.Type, sync.Method);
                }

                AsyncMethodInvoker async = this.invoker as AsyncMethodInvoker; 
                if (async != null)
                { 
                    this.ValidateInstanceType(operation.Parent.Type, async.BeginMethod); 
                    this.ValidateInstanceType(operation.Parent.Type, async.EndMethod);
                } 
            }
        }

        internal string Action 
        {
            get { return this.action; } 
        } 

        internal ICallContextInitializer[] CallContextInitializers 
        {
            get { return this.callContextInitializers; }
        }
 
        internal bool DisposeParameters
        { 
            get { return this.disposeParameters; } 
        }
 
        internal bool HasDefaultUnhandledActionInvoker
        {
            get { return (this.invoker is DispatchRuntime.UnhandledActionInvoker); }
        } 

        internal bool SerializeReply 
        { 
            get { return this.serializeReply; }
        } 

        internal IDispatchFaultFormatter FaultFormatter
        {
            get { return this.faultFormatter; } 
        }
 
        internal IDispatchMessageFormatter Formatter 
        {
            get { return this.formatter; } 
        }

        internal ImpersonationOption Impersonation
        { 
            get { return this.impersonation; }
        } 
 
        internal IOperationInvoker Invoker
        { 
            get { return this.invoker; }
        }

        internal bool IsSynchronous 
        {
            get { return this.isSynchronous; } 
        } 

        internal bool IsOneWay 
        {
            get { return this.isOneWay; }
        }
 
        internal bool IsTerminating
        { 
            get { return this.isTerminating; } 
        }
 
        internal string Name
        {
            get { return this.name; }
        } 

        internal IParameterInspector[] ParameterInspectors 
        { 
            get { return this.inspectors; }
        } 

        internal ImmutableDispatchRuntime Parent
        {
            get { return this.parent; } 
        }
 
        internal bool ReleaseInstanceAfterCall 
        {
            get { return this.releaseInstanceAfterCall; } 
        }

        internal bool ReleaseInstanceBeforeCall
        { 
            get { return this.releaseInstanceBeforeCall; }
        } 
 
        internal string ReplyAction
        { 
            get { return this.replyAction; }
        }

        internal bool TransactionAutoComplete 
        {
            get { return this.transactionAutoComplete; } 
        } 

        internal bool TransactionRequired 
        {
            get { return this.transactionRequired; }
        }
 
        void DeserializeInputs(ref MessageRpc rpc)
        { 
            bool success = false; 
            try
            { 
                try
                {
                    rpc.InputParameters = this.Invoker.AllocateInputs();
                } 
                catch (Exception e)
                { 
                    if (DiagnosticUtility.IsFatal(e)) 
                    {
                        throw; 
                    }
                    if (ErrorBehavior.ShouldRethrowExceptionAsIs(e))
                    {
                        throw; 
                    }
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperCallback(e); 
                } 
                try
                { 
                    if (this.deserializeRequest)
                    {
                        this.Formatter.DeserializeRequest(rpc.Request, rpc.InputParameters);
                    } 
                    else
                    { 
                        rpc.InputParameters[0] = rpc.Request; 
                    }
 
                    success = true;
                }
                catch (Exception e)
                { 
                    if (DiagnosticUtility.IsFatal(e))
                    { 
                        throw; 
                    }
                    if (ErrorBehavior.ShouldRethrowExceptionAsIs(e)) 
                    {
                        throw;
                    }
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperCallback(e); 
                }
            } 
            finally 
            {
                rpc.DidDeserializeRequestBody = (rpc.Request.State != MessageState.Created); 

                if (!success && MessageLogger.LoggingEnabled)
                {
                    MessageLogger.LogMessage(ref rpc.Request, MessageLoggingSource.Malformed); 
                }
            } 
        } 

        void InitializeCallContext(ref MessageRpc rpc) 
        {
            if (this.CallContextInitializers.Length > 0)
            {
                InitializeCallContextCore(ref rpc); 
            }
        } 
 
        void InitializeCallContextCore(ref MessageRpc rpc)
        { 
            IClientChannel channel = rpc.Channel.Proxy as IClientChannel;
            int offset = this.Parent.CallContextCorrelationOffset;

            try 
            {
                for (int i = 0; i < rpc.Operation.CallContextInitializers.Length; i++) 
                { 
                    ICallContextInitializer initializer = this.CallContextInitializers[i];
                    rpc.Correlation[offset + i] = initializer.BeforeInvoke(rpc.InstanceContext, channel, rpc.Request); 
                }
            }
            catch (Exception e)
            { 
                if (DiagnosticUtility.IsFatal(e))
                { 
                    throw; 
                }
                if (ErrorBehavior.ShouldRethrowExceptionAsIs(e)) 
                {
                    throw;
                }
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperCallback(e); 
            }
        } 
 
        void UninitializeCallContext(ref MessageRpc rpc)
        { 
            if (this.CallContextInitializers.Length > 0)
            {
                UninitializeCallContextCore(ref rpc);
            } 
        }
 
        void UninitializeCallContextCore(ref MessageRpc rpc) 
        {
            IClientChannel channel = rpc.Channel.Proxy as IClientChannel; 
            int offset = this.Parent.CallContextCorrelationOffset;

            try
            { 
                for (int i = this.CallContextInitializers.Length - 1; i >= 0; i--)
                { 
                    ICallContextInitializer initializer = this.CallContextInitializers[i]; 
                    initializer.AfterInvoke(rpc.Correlation[offset + i]);
                } 
            }
            catch (Exception e)
            {
                // thread-local storage may be corrupt 
                DiagnosticUtility.FailFast(string.Format(CultureInfo.InvariantCulture, "ICallContextInitializer.BeforeInvoke threw an exception of type {0}: {1}", e.GetType(), e.Message));
            } 
        } 

        void InspectInputs(ref MessageRpc rpc) 
        {
            if (this.ParameterInspectors.Length > 0)
            {
                InspectInputsCore(ref rpc); 
            }
        } 
 
        void InspectInputsCore(ref MessageRpc rpc)
        { 
            int offset = this.Parent.ParameterInspectorCorrelationOffset;

            for (int i = 0; i < this.ParameterInspectors.Length; i++)
            { 
                IParameterInspector inspector = this.ParameterInspectors[i];
                rpc.Correlation[offset + i] = inspector.BeforeCall(this.Name, rpc.InputParameters); 
            } 
        }
 
        void InspectOutputs(ref MessageRpc rpc)
        {
            if (this.ParameterInspectors.Length > 0)
            { 
                InspectOutputsCore(ref rpc);
            } 
        } 

        void InspectOutputsCore(ref MessageRpc rpc) 
        {
            int offset = this.Parent.ParameterInspectorCorrelationOffset;

            for (int i = this.ParameterInspectors.Length - 1; i >= 0; i--) 
            {
                IParameterInspector inspector = this.ParameterInspectors[i]; 
                inspector.AfterCall(this.Name, rpc.OutputParameters, rpc.ReturnParameter, rpc.Correlation[offset + i]); 
            }
        } 

        /// 
        /// Critical - calls SecurityCritical method StartImpersonation
        /// Safe - manages the result of impersonation and properly Disposes it 
        /// 
        [DebuggerStepperBoundary] 
        [SecurityCritical, SecurityTreatAsSafe] 
        internal void InvokeBegin(ref MessageRpc rpc)
        { 
            if (rpc.Error == null)
            {
                try
                { 
                    this.InitializeCallContext(ref rpc);
                    object target = rpc.Instance; 
                    this.DeserializeInputs(ref rpc); 
                    this.InspectInputs(ref rpc);
 
                    ValidateMustUnderstand(ref rpc);

                    IAsyncResult result = null;
                    IDisposable impersonationContext = null; 
                    IPrincipal originalPrincipal = null;
                    bool isThreadPrincipalSet = false; 
 
                    try
                    { 
                        if (this.parent.SecurityImpersonation != null)
                        {
                            this.parent.SecurityImpersonation.StartImpersonation(ref rpc, out impersonationContext, out originalPrincipal, out isThreadPrincipalSet);
                        } 

                        if (this.isSynchronous) 
                        { 
                            rpc.ReturnParameter = this.Invoker.Invoke(target, rpc.InputParameters, out rpc.OutputParameters);
                        } 
                        else
                        {
                            bool isBeginSuccessful = false;
                            IResumeMessageRpc resumeRpc = rpc.Pause(); 
                            try
                            { 
                                result = this.Invoker.InvokeBegin(target, rpc.InputParameters, invokeCallback, resumeRpc); 
                                isBeginSuccessful = true;
                                // if the call above actually went async, then responsibility to call 
                                // ProcessMessage{6,7,Cleanup} has been transferred to InvokeCallback
                            }
                            finally
                            { 
                                if (!isBeginSuccessful)
                                { 
                                    rpc.UnPause(); 
                                }
                            } 
                        }
                    }
                    finally
                    { 
                        try
                        { 
                            if (this.parent.SecurityImpersonation != null) 
                            {
                                this.parent.SecurityImpersonation.StopImpersonation(ref rpc, impersonationContext, originalPrincipal, isThreadPrincipalSet); 
                            }
                        }
#pragma warning suppress 56500 // covered by FxCOP
                        catch 
                        {
                            string message = null; 
                            try 
                            {
                                message = SR.GetString(SR.SFxRevertImpersonationFailed0); 
                            }
                            finally
                            {
                                DiagnosticUtility.FailFast(message); 
                            }
                        } 
                    } 

                    if (this.isSynchronous) 
                    {
                        this.InspectOutputs(ref rpc);
                        this.SerializeOutputs(ref rpc);
                    } 
                    else
                    { 
                        if (result == null) 
                        {
                            throw TraceUtility.ThrowHelperError(new ArgumentNullException("IOperationInvoker.BeginDispatch"), rpc.Request); 
                        }

                        if (rpc.CompletedSynchronously.Value)
                        { 
                            // if the async call completed synchronously, then the responsibility to call
                            // ProcessMessage{6,7,Cleanup} still remains on this thread 
                            rpc.UnPause(); 
                            rpc.AsyncResult = result;
                        } 
                    }
                }
#pragma warning suppress 56500 // covered by FxCOP
                catch { throw; } // Make sure user Exception filters are not impersonated. 
                finally
                { 
                    this.UninitializeCallContext(ref rpc); 
                }
            } 
        }

        static void InvokeCallback(IAsyncResult result)
        { 
            IResumeMessageRpc resume = result.AsyncState as IResumeMessageRpc;
 
            if (resume == null) 
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(SR.GetString(SR.SFxInvalidAsyncResultState0)); 
            }

            if (ImmutableDispatchRuntime.processMessage5IsOnTheStack == resume.AsyncOperationWaitEvent)
            { 
                // If TLS is marked with the object associated with the current MessageRpc, then we know that
                // the async operation completed sync.  Note this, and then return, so as to unwind the stack 
                // back down to ProcessMessage5, which will finish processing this MessageRpc. 
                resume.SetCompletedSynchronously();
                return; 
            }
            else
            {
                // This thread is responsible for the rest of the processing of this MessageRpc. 
                resume.Resume(result);
            } 
        } 

        ///  
        /// Critical - calls SecurityCritical method StartImpersonation
        /// Safe - manages the result of impersonation and properly Disposes it
        /// 
        [DebuggerStepperBoundary] 
        [SecurityCritical, SecurityTreatAsSafe]
        internal void InvokeEnd(ref MessageRpc rpc) 
        { 
            if ((rpc.Error == null) && !this.isSynchronous)
            { 
                try
                {
                    this.InitializeCallContext(ref rpc);
 
                    IDisposable impersonationContext = null;
                    IPrincipal originalPrincipal = null; 
                    bool isThreadPrincipalSet = false; 

                    try 
                    {
                        if (this.parent.SecurityImpersonation != null)
                        {
                            this.parent.SecurityImpersonation.StartImpersonation(ref rpc, out impersonationContext, out originalPrincipal, out isThreadPrincipalSet); 
                        }
 
                        rpc.ReturnParameter = this.Invoker.InvokeEnd(rpc.Instance, out rpc.OutputParameters, rpc.AsyncResult); 
                    }
                    finally 
                    {
                        try
                        {
                            if (this.parent.SecurityImpersonation != null) 
                            {
                                this.parent.SecurityImpersonation.StopImpersonation(ref rpc, impersonationContext, originalPrincipal, isThreadPrincipalSet); 
                            } 
                        }
#pragma warning suppress 56500 // covered by FxCOP 
                        catch
                        {
                            string message = null;
                            try 
                            {
                                message = SR.GetString(SR.SFxRevertImpersonationFailed0); 
                            } 
                            finally
                            { 
                                DiagnosticUtility.FailFast(message);
                            }
                        }
                    } 

                    this.InspectOutputs(ref rpc); 
                    this.SerializeOutputs(ref rpc); 
                }
#pragma warning suppress 56500 // covered by FxCOP 
                catch { throw; } // Make sure user Exception filters are not impersonated.
                finally
                {
                    this.UninitializeCallContext(ref rpc); 
                }
            } 
        } 

        void SerializeOutputs(ref MessageRpc rpc) 
        {
            if (!this.IsOneWay && this.parent.EnableFaults)
            {
                Message reply; 
                if (this.serializeReply)
                { 
                    try 
                    {
                        reply = this.Formatter.SerializeReply(rpc.RequestVersion, rpc.OutputParameters, rpc.ReturnParameter); 
                    }
                    catch (Exception e)
                    {
                        if (DiagnosticUtility.IsFatal(e)) 
                        {
                            throw; 
                        } 
                        if (ErrorBehavior.ShouldRethrowExceptionAsIs(e))
                        { 
                            throw;
                        }
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperCallback(e);
                    } 

                    if (reply == null) 
                    { 
                        string message = SR.GetString(SR.SFxNullReplyFromFormatter2, this.Formatter.GetType().ToString(), (this.name ?? ""));
                        ErrorBehavior.ThrowAndCatch(new InvalidOperationException(message)); 
                    }
                }
                else
                { 
                    if ((rpc.ReturnParameter == null) && (rpc.OperationContext.RequestContext != null))
                    { 
                        string message = SR.GetString(SR.SFxDispatchRuntimeMessageCannotBeNull, this.name); 
                        ErrorBehavior.ThrowAndCatch(new InvalidOperationException(message));
                    } 

                    reply = (Message)rpc.ReturnParameter;

                    if ((reply != null) && (!ProxyOperationRuntime.IsValidAction(reply, this.ReplyAction))) 
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxInvalidReplyAction, this.Name, reply.Headers.Action ?? "{NULL}", this.ReplyAction))); 
                    } 
                }
 
                if (DiagnosticUtility.ShouldUseActivity && rpc.Activity != null && reply != null)
                {
                    TraceUtility.SetActivity(reply, rpc.Activity);
                    if (TraceUtility.ShouldPropagateActivity) 
                    {
                        TraceUtility.AddActivityHeader(reply); 
                    } 
                }
                else if (TraceUtility.ShouldPropagateActivity && reply != null && rpc.ResponseActivityId != Guid.Empty) 
                {
                    ActivityIdHeader header = new ActivityIdHeader(rpc.ResponseActivityId);
                    header.AddTo(reply);
                } 
                if (MessageLogger.LoggingEnabled && null != reply)
                { 
                    MessageLogger.LogMessage(ref reply, MessageLoggingSource.ServiceLevelSendReply | MessageLoggingSource.LastChance); 
                }
                rpc.Reply = reply; 
            }
        }

        void ValidateInstanceType(Type type, MethodInfo method) 
        {
            if (!method.DeclaringType.IsAssignableFrom(type)) 
            { 
                string message = SR.GetString(SR.SFxMethodNotSupportedByType2,
                                              type.FullName, 
                                              method.DeclaringType.FullName);

                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(message));
            } 
        }
 
        void ValidateMustUnderstand(ref MessageRpc rpc) 
        {
            if (parent.ValidateMustUnderstand) 
            {
                rpc.NotUnderstoodHeaders = rpc.Request.Headers.GetHeadersNotUnderstood();
                if (rpc.NotUnderstoodHeaders != null)
                { 
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                        new MustUnderstandSoapException(rpc.NotUnderstoodHeaders, rpc.Request.Version.Envelope)); 
                } 
            }
        } 
    }
}

// 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