File: System\ServiceModel\Dispatcher\WorkflowOperationInvoker.cs
Project: ndp\cdf\src\NetFx35\System.WorkflowServices\System.WorkflowServices.csproj (System.WorkflowServices)
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//------------------------------------------------------------
namespace System.ServiceModel.Dispatcher
{
    using System.Diagnostics;
    using System.Reflection;
    using System.Runtime;
    using System.Security;
    using System.ServiceModel.Channels;
    using System.ServiceModel.Description;
    using System.ServiceModel.Diagnostics;
    using System.Workflow.Runtime;
 
    class WorkflowOperationInvoker : IOperationInvoker
    {
        static object[] emptyObjectArray = new object[0];
        bool canCreateInstance;
        DispatchRuntime dispatchRuntime;
        int inParameterCount;
        bool isOneWay;
        OperationDescription operationDescription;
        ServiceAuthorizationManager serviceAuthorizationManager;
        string staticQueueName;
        MethodInfo syncMethod;
        WorkflowInstanceLifetimeManagerExtension workflowInstanceLifeTimeManager;
        WorkflowRuntime workflowRuntime;
 
        public WorkflowOperationInvoker(OperationDescription operationDescription, WorkflowOperationBehavior workflowOperationBehavior,
            WorkflowRuntime workflowRuntime, DispatchRuntime dispatchRuntime)
        {
            if (operationDescription == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("operationDescription");
            }
 
            if (workflowRuntime == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("workflowRuntime");
            }
 
            if (workflowOperationBehavior == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("workflowOperationBehavior");
            }
 
            this.isOneWay = operationDescription.IsOneWay;
 
            if (operationDescription.BeginMethod != null)
            {
                this.syncMethod = operationDescription.BeginMethod;
                inParameterCount = GetFlowedInParameterCount(operationDescription.BeginMethod.GetParameters()) - 2;
            }
            else
            {
                this.syncMethod = operationDescription.SyncMethod;
                inParameterCount = GetFlowedInParameterCount(operationDescription.SyncMethod.GetParameters());
            }
 
            this.operationDescription = operationDescription;
            this.workflowRuntime = workflowRuntime;
            this.canCreateInstance = workflowOperationBehavior.CanCreateInstance;
            this.serviceAuthorizationManager = workflowOperationBehavior.ServiceAuthorizationManager;
            this.dispatchRuntime = dispatchRuntime;
            staticQueueName = QueueNameHelper.Create(this.syncMethod.DeclaringType, operationDescription.Name);
        }
 
        public bool CanCreateInstance
        {
            get { return this.canCreateInstance; }
        }
 
        public DispatchRuntime DispatchRuntime
        {
            get { return this.dispatchRuntime; }
        }
 
        public WorkflowInstanceLifetimeManagerExtension InstanceLifetimeManager
        {
            get
            {
                if (this.workflowInstanceLifeTimeManager == null)
                {
                    this.workflowInstanceLifeTimeManager = this.dispatchRuntime.ChannelDispatcher.Host.Extensions.Find<WorkflowInstanceLifetimeManagerExtension>();
                }
 
                return this.workflowInstanceLifeTimeManager;
            }
        }
 
        public bool IsOneWay
        {
            get { return this.isOneWay; }
        }
 
        public bool IsSynchronous
        {
            get { return false; }
        }
 
        public string StaticQueueName
        {
            get { return this.staticQueueName; }
        }
 
        public object[] AllocateInputs()
        {
            if (inParameterCount == 0)
            {
                return emptyObjectArray;
            }
            return new object[inParameterCount];
        }
 
        public object Invoke(object instance, object[] inputs, out object[] outputs)
        {
            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotImplementedException());
        }
 
        public IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state)
        {
            long beginTime = 0;
 
            if (PerformanceCounters.PerformanceCountersEnabled)
            {
                PerformanceCounters.MethodCalled(this.operationDescription.Name);
 
                try
                {
                    if (UnsafeNativeMethods.QueryPerformanceCounter(out beginTime) == 0)
                    {
                        beginTime = -1;
                    }
                }
                catch (SecurityException exception)
                {
                    DiagnosticUtility.TraceHandledException(exception, TraceEventType.Warning);
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityException(SR.GetString("PartialTrustPerformanceCountersNotEnabled"), exception));
                }
            }
 
            Authorize();
 
            WorkflowDurableInstance durableInstance = (WorkflowDurableInstance) instance;
 
            Fx.Assert(durableInstance.CurrentOperationInvocation == null,
                "At the time WorkflowOperationInvoker.InvokeBegin is called, the WorkflowDurableInstance.CurrentOperationInvocation is expected to be null given the ConcurrencyMode.Single.");
 
            durableInstance.CurrentOperationInvocation = new WorkflowOperationAsyncResult(
                this,
                durableInstance,
                inputs,
                callback,
                state,
                beginTime);
 
            return durableInstance.CurrentOperationInvocation;
        }
 
        public object InvokeEnd(object instance, out object[] outputs, IAsyncResult result)
        {
            bool methodThrewException = false;
 
            if (result == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("result");
            }
 
            WorkflowDurableInstance durableInstance = (WorkflowDurableInstance) instance;
            WorkflowOperationAsyncResult asyncResult = (WorkflowOperationAsyncResult) result;
 
            Fx.Assert(durableInstance.CurrentOperationInvocation != null,
                "At the time WorkflowOperationInvoker.InvokeEnd is called, the WorkflowDurableInstance.CurrentOperationInvocation is expected to be present.");
 
            try
            {
                return WorkflowOperationAsyncResult.End(asyncResult, out outputs);
            }
            catch (FaultException)
            {
                methodThrewException = true;
                if (PerformanceCounters.PerformanceCountersEnabled)
                {
                    PerformanceCounters.MethodReturnedFault(this.operationDescription.Name);
                }
                throw;
            }
            catch (Exception e)
            {
                methodThrewException = true;
 
                if (Fx.IsFatal(e))
                {
                    throw;
                }
 
                if (PerformanceCounters.PerformanceCountersEnabled)
                {
                    PerformanceCounters.MethodReturnedError(this.operationDescription.Name);
                }
                throw;
            }
            finally
            {
                durableInstance.CurrentOperationInvocation = null;
 
                if (!methodThrewException)
                {
                    if (PerformanceCounters.PerformanceCountersEnabled)
                    {
                        long currentTime = 0;
                        long duration = 0;
 
                        if ((asyncResult.BeginTime >= 0) && (UnsafeNativeMethods.QueryPerformanceCounter(out currentTime) != 0))
                        {
                            duration = currentTime - asyncResult.BeginTime;
                        }
                        PerformanceCounters.MethodReturnedSuccess(this.operationDescription.Name, duration);
                    }
                }
            }
        }
 
        static int GetFlowedInParameterCount(System.Reflection.ParameterInfo[] parameterInfos)
        {
            int inputCount = 0;
 
            foreach (System.Reflection.ParameterInfo parameterInfo in parameterInfos)
            {
                if (parameterInfo.IsOut)
                {
                    if (parameterInfo.IsIn)
                    {
                        ++inputCount;
                    }
                }
                else
                {
                    ++inputCount;
                }
            }
            return inputCount;
        }
 
        void Authorize()
        {
            Fx.Assert(OperationContext.Current != null, "Not in service dispatch thread");
 
            if (this.serviceAuthorizationManager != null)
            {
                if (!this.serviceAuthorizationManager.CheckAccess(OperationContext.Current))
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(AuthorizationBehavior.CreateAccessDeniedFaultException());
                }
            }
        }
    }
}