ControlOperationInvoker.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / cdf / src / NetFx40 / System.ServiceModel.Activities / System / ServiceModel / Activities / Dispatcher / ControlOperationInvoker.cs / 1407647 / ControlOperationInvoker.cs

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

namespace System.ServiceModel.Activities.Dispatcher 
{
    using System.Activities; 
    using System.Collections; 
    using System.Collections.Generic;
    using System.Collections.ObjectModel; 
    using System.ComponentModel;
    using System.Runtime;
    using System.Runtime.DurableInstancing;
    using System.ServiceModel.Activities; 
    using System.ServiceModel.Channels;
    using System.ServiceModel.Description; 
    using System.ServiceModel.Dispatcher; 
    using System.Transactions;
    using System.Xml.Linq; 

    //This will be the top most invoker for all endpoint operations for durable services.
    //It operates in 3 modes.
    //1) IWorkflowInstanceManagement endpoint operation(completely implemented by this type) 
    //2) Application endpoint(Modelled Receive/DurableService) Custom invoker inherited from this type overriding OnBegin/End ServiceOperation.
    //3) Durable Standard Endpoint(LRCS/Interop/Delay) eventual dispatch call will be delegated to innerInvoker with DurableInstanceContext as service object. 
 
    //This class is single point of interaction with DurableInstanceManagement and ensures appropriate DurableInstance for the request, based on the mode of operation
    //message will be dispatched to various part of DurableInstance. 
    class ControlOperationInvoker : IManualConcurrencyOperationInvoker
    {
        protected static readonly object[] emptyObjectArray = new object[0];
 
        readonly DurableInstanceManager instanceManager;
        readonly string operationName; 
        readonly bool isOneWay; 
        readonly ServiceEndpoint endpoint;
        readonly int inputParameterCount; 

        readonly IOperationInvoker innerInvoker;
        readonly bool isControlOperation;
        readonly CorrelationKeyCalculator keyCalculator; 

        readonly WorkflowServiceHost host; 
        readonly BufferedReceiveManager bufferedReceiveManager; 
        readonly TimeSpan persistTimeout;
 
        public ControlOperationInvoker(OperationDescription description, ServiceEndpoint endpoint,
            CorrelationKeyCalculator correlationKeyCalculator, ServiceHostBase host)
            : this(description, endpoint, correlationKeyCalculator, null, host)
        { 
        }
 
        public ControlOperationInvoker(OperationDescription description, ServiceEndpoint endpoint, 
            CorrelationKeyCalculator correlationKeyCalculator, IOperationInvoker innerInvoker, ServiceHostBase host)
        { 
            Fx.Assert(host is WorkflowServiceHost, "ControlOperationInvoker must be used with a WorkflowServiceHost");

            this.host = (WorkflowServiceHost)host;
            this.instanceManager = this.host.DurableInstanceManager; 
            this.operationName = description.Name;
            this.isOneWay = description.IsOneWay; 
            this.endpoint = endpoint; 
            this.innerInvoker = innerInvoker;
            this.keyCalculator = correlationKeyCalculator; 
            this.persistTimeout = this.host.PersistTimeout;

            if (description.DeclaringContract == WorkflowControlEndpoint.WorkflowControlServiceContract)
            { 
                //Mode1: This invoker belongs to IWorkflowInstanceManagement operation.
                this.isControlOperation = true; 
                switch (this.operationName) 
                {
                    case XD2.WorkflowInstanceManagementService.Cancel: 
                    case XD2.WorkflowInstanceManagementService.TransactedCancel:
                    case XD2.WorkflowInstanceManagementService.Run:
                    case XD2.WorkflowInstanceManagementService.TransactedRun:
                    case XD2.WorkflowInstanceManagementService.Unsuspend: 
                    case XD2.WorkflowInstanceManagementService.TransactedUnsuspend:
                        this.inputParameterCount = 1; 
                        break; 
                    case XD2.WorkflowInstanceManagementService.Abandon:
                    case XD2.WorkflowInstanceManagementService.Suspend: 
                    case XD2.WorkflowInstanceManagementService.TransactedSuspend:
                    case XD2.WorkflowInstanceManagementService.Terminate:
                    case XD2.WorkflowInstanceManagementService.TransactedTerminate:
                        this.inputParameterCount = 2; 
                        break;
                    default: 
                        throw Fx.AssertAndThrow("Unreachable code"); 
                }
            } 
            else if (endpoint is WorkflowHostingEndpoint)
            {
                this.CanCreateInstance = true;
            } 
            else
            { 
                this.bufferedReceiveManager = this.host.Extensions.Find(); 
            }
        } 

        public bool IsSynchronous { get { return false; } }

        protected bool CanCreateInstance { get; set; } 
        protected string StaticBookmarkName { get; set; }
 
        protected string OperationName 
        {
            get { return this.operationName; } 
        }

        public BufferedReceiveManager BufferedReceiveManager
        { 
            get { return this.bufferedReceiveManager; }
        } 
 
        public DurableInstanceManager InstanceManager
        { 
            get { return this.instanceManager; }
        }

        public virtual object[] AllocateInputs() 
        {
            if (this.innerInvoker != null) //Mode 3: Delegate call to innerInvoker. 
            { 
                return this.innerInvoker.AllocateInputs();
            } 
            else if (this.isControlOperation) //Mode 1
            {
                if (this.inputParameterCount == 0)
                { 
                    return emptyObjectArray;
                } 
                else 
                {
                    return new object[this.inputParameterCount]; 
                }
            }
            //Mode 2: Derived invoker should ensure appropriate in parameter count based on its contract.
            throw Fx.AssertAndThrow("Derived invoker should have handled this case"); 
        }
 
        // We own the formatter only if the message is oneway and is used 
        // to detemine if the message needs to be disposed or not.
        bool IManualConcurrencyOperationInvoker.OwnsFormatter 
        {
            get { return this.isOneWay; }
        }
 
        public object Invoke(object instance, object[] inputs, out object[] outputs)
        { 
            return Invoke(instance, inputs, null, out outputs); 
        }
 
        public object Invoke(object instance, object[] inputs, IInvokeReceivedNotification notification, out object[] outputs)
        {
            throw FxTrace.Exception.AsError(new NotImplementedException());
        } 

        public IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state) 
        { 
            return InvokeBegin(instance, inputs, null, callback, state);
        } 

        public IAsyncResult InvokeBegin(object instance, object[] inputs, IInvokeReceivedNotification notification, AsyncCallback callback, object state)
        {
            if (inputs == null) 
            {
                throw FxTrace.Exception.ArgumentNull("inputs"); 
            } 

            //Fetch Instance and Dispatch. 
            return new ControlOperationAsyncResult(this, inputs, notification, TimeSpan.MaxValue, callback, state);
        }

        public object InvokeEnd(object instance, out object[] outputs, IAsyncResult result) 
        {
            return ControlOperationAsyncResult.End(out outputs, result); 
        } 

        //This is the dispatch call for Non-IWorkflowInstanceManagement Operations. 
        protected virtual IAsyncResult OnBeginServiceOperation(WorkflowServiceInstance durableInstance,
            OperationContext operationContext, object[] inputs, Transaction currentTransaction, IInvokeReceivedNotification notification,
            TimeSpan timeout, AsyncCallback callback, object state)
        { 
            return new ServiceOperationAsyncResult(this.innerInvoker, durableInstance, inputs, operationContext, currentTransaction, notification,
                callback, state); 
        } 
        protected virtual object OnEndServiceOperation(WorkflowServiceInstance durableInstance, out object[] outputs, IAsyncResult result)
        { 
            return ServiceOperationAsyncResult.End(out outputs, result);
        }

 
        // pass OperationContext.Current if you don't already have an OperationContext.
        protected void GetInstanceKeys(OperationContext operationContext, out InstanceKey instanceKey, out ICollection additionalKeys) 
        { 
            CorrelationMessageProperty correlationMessageProperty = null;
            InstanceKey localInstanceKey; 
            ICollection localAdditionalKeys;

            instanceKey = InstanceKey.InvalidKey;
            additionalKeys = new ReadOnlyCollection(new InstanceKey[] { }); 

            if (!CorrelationMessageProperty.TryGet(operationContext.IncomingMessageProperties, 
                out correlationMessageProperty)) 
            {
                if (this.keyCalculator != null) 
                {
                    MessageBuffer requestMessageBuffer;
                    bool success;
 
                    if (operationContext.IncomingMessageProperties.TryGetValue(ChannelHandler.MessageBufferPropertyName, out requestMessageBuffer))
                    { 
                        success = this.keyCalculator.CalculateKeys(requestMessageBuffer, operationContext.IncomingMessage, out localInstanceKey, out localAdditionalKeys); 
                    }
                    else 
                    {
                        // Message is not preserved.(DispatchRuntime.PreserveMessage is false.)
                        // this could be a case where we only have context queries, in this case we don't preserve the message
                        success = this.keyCalculator.CalculateKeys(operationContext.IncomingMessage, out localInstanceKey, out localAdditionalKeys); 
                    }
                    if (success) 
                    { 
                        if (localInstanceKey != null)
                        { 
                            instanceKey = localInstanceKey;
                        }
                        if (localAdditionalKeys != null)
                        { 
                            additionalKeys = localAdditionalKeys;
                        } 
 
                        correlationMessageProperty = new CorrelationMessageProperty(instanceKey, additionalKeys);
 
                        operationContext.IncomingMessageProperties.Add(CorrelationMessageProperty.Name, correlationMessageProperty);
                    }
                }
            } 
            else
            { 
                instanceKey = correlationMessageProperty.CorrelationKey; 
                additionalKeys = correlationMessageProperty.AdditionalKeys;
            } 

            //If InstanceKey is still not resolved do the activation operation validation.
            if (instanceKey == null || !instanceKey.IsValid)
            { 
                if (!this.CanCreateInstance)
                { 
                    this.host.RaiseUnknownMessageReceived(operationContext.IncomingMessage); 

                    throw FxTrace.Exception.AsError( 
                        new FaultException(
                        new DurableDispatcherAddressingFault()));
                }
            } 
        }
 
 
        class ControlOperationAsyncResult : AsyncResult
        { 
            static AsyncCompletion handleEndGetInstance = new AsyncCompletion(HandleEndGetInstance);
            static AsyncCompletion handleEndOperation = new AsyncCompletion(HandleEndOperation);
            static AsyncCompletion handleEndAbandonReceiveContext;
            static ReadOnlyCollection emptyKeyCollection = new ReadOnlyCollection(new InstanceKey[] { }); 
            static Action onCompleting = new Action(Finally);
 
            object[] inputs; 
            TimeoutHelper timeoutHelper;
 
            Guid instanceId;
            InstanceKey instanceKey = InstanceKey.InvalidKey;
            ICollection additionalKeys = emptyKeyCollection;
 
            WorkflowServiceInstance workflowServiceInstance;
            Transaction transaction; 
            ReceiveContext receiveContext; 
            Exception operationException;
 
            object returnValue;
            OperationContext operationContext;

            ControlOperationInvoker invoker; 
            IInvokeReceivedNotification notification;
 
            object[] outputs = emptyObjectArray; 

            WorkflowGetInstanceContext getInstanceContext; 

            public ControlOperationAsyncResult(ControlOperationInvoker invoker, object[] inputs, IInvokeReceivedNotification notification, TimeSpan timeout,
                AsyncCallback callback, object state)
                : base(callback, state) 
            {
                this.invoker = invoker; 
                this.inputs = inputs; 
                this.timeoutHelper = new TimeoutHelper(timeout);
                this.transaction = Transaction.Current; 
                this.operationContext = OperationContext.Current;
                this.OnCompleting = onCompleting;

                bool completeSelf = false; 
                bool success = false;
                try 
                { 
                    if (notification != null)
                    { 
                        if (this.operationContext.SessionId == null)
                        {
                            // Datagram messages are completely concurrent to loadOrCreate and instance operations. Same as WCF's ConcurrencyMode.Single
                            notification.NotifyInvokeReceived(); 
                        }
                        else 
                        { 
                            // For session, we will notify after we enter into WorkflowServiceInstance pending queue.
                            // This achieves synchronization and ordered messages within a session and concurrent across distinct sessions. 
                            this.notification = notification;
                        }
                    }
 
                    if (invoker.BufferedReceiveManager != null)
                    { 
                        if (!ReceiveContext.TryGet(this.operationContext.IncomingMessageProperties, out this.receiveContext)) 
                        {
                            Fx.Assert("ReceiveContext expected when BufferedReceives are enabled"); 
                        }
                    }

                    completeSelf = this.Process(); 
                    success = true;
                } 
                finally 
                {
                    // in the success cases, OnCompleting has us covered 
                    if (!success)
                    {
                        Finally(this, null);
                    } 
                }
 
                if (completeSelf) 
                {
                    this.Complete(true); 
                }
            }

            static void Finally(AsyncResult result, Exception completionException) 
            {
                ControlOperationAsyncResult thisPtr = (ControlOperationAsyncResult)result; 
                if (thisPtr.workflowServiceInstance != null) 
                {
                    thisPtr.workflowServiceInstance.ReleaseReference(); 
                    thisPtr.workflowServiceInstance = null;
                }
                if (completionException != null)
                { 
                    thisPtr.invoker.host.FaultServiceHostIfNecessary(completionException);
                } 
            } 

            public static object End(out object[] outputs, IAsyncResult result) 
            {
                ControlOperationAsyncResult thisPtr = AsyncResult.End(result);
                outputs = thisPtr.outputs;
                return thisPtr.returnValue; 
            }
 
            bool Process() 
            {
                EnsureInstanceId(); 

                this.getInstanceContext = new WorkflowGetInstanceContext
                {
                    WorkflowHostingEndpoint = this.invoker.endpoint as WorkflowHostingEndpoint, 
                    CanCreateInstance = this.invoker.CanCreateInstance,
                    Inputs = this.inputs, 
                    OperationContext = this.operationContext, 
                };
 
                IAsyncResult result;

                bool shouldAbandon = true;
                try 
                {
                    try 
                    { 
                        if (!this.invoker.isControlOperation && this.instanceKey != null && this.instanceKey.IsValid)
                        { 
                            result = this.invoker.instanceManager.BeginGetInstance(this.instanceKey, this.additionalKeys, this.getInstanceContext,
                                this.invoker.persistTimeout, this.PrepareAsyncCompletion(handleEndGetInstance), this);
                        }
                        else 
                        {
                            result = this.invoker.instanceManager.BeginGetInstance(this.instanceId, this.getInstanceContext, 
                                this.invoker.persistTimeout, this.PrepareAsyncCompletion(handleEndGetInstance), this); 
                        }
                        shouldAbandon = false; 
                    }
                    catch (InstanceLockedException exception)
                    {
                        RedirectionException redirectionException; 
                        if (TryCreateRedirectionException(exception, out redirectionException))
                        { 
                            throw FxTrace.Exception.AsError(redirectionException); 
                        }
                        throw FxTrace.Exception.AsError(CreateFaultException(exception)); 
                    }
                    catch (OperationCanceledException exception)
                    {
                        BufferReceiveHelper(ref shouldAbandon, true); 
                        throw FxTrace.Exception.AsError(new RetryException(null, exception));
                    } 
                    catch (InstancePersistenceException exception) 
                    {
                        BufferReceiveHelper(ref shouldAbandon, false); 

                        if (exception is InstanceKeyNotReadyException)
                        {
                            this.invoker.host.RaiseUnknownMessageReceived(this.operationContext.IncomingMessage); 
                        }
 
                        this.invoker.host.FaultServiceHostIfNecessary(exception); 

                        throw FxTrace.Exception.AsError(CreateFaultException(exception)); 
                    }
                }
                catch (Exception exception)
                { 
                    if (Fx.IsFatal(exception))
                    { 
                        throw; 
                    }
                    if (!shouldAbandon || !ShouldAbandonReceiveContext()) 
                    {
                        throw;
                    }
                    return AbandonReceiveContext(exception); 
                }
 
                if (result.CompletedSynchronously) 
                {
                    return HandleEndGetInstance(result); 
                }
                return false;
            }
 
            void BufferReceiveHelper(ref bool shouldAbandon, bool retry)
            { 
                if (this.invoker.BufferedReceiveManager != null) 
                {
                    Fx.Assert(this.receiveContext != null, "receiveContext must not be null!"); 
                    bool bufferSuccess = this.invoker.BufferedReceiveManager.BufferReceive(
                        this.operationContext, this.receiveContext, this.invoker.StaticBookmarkName, BufferedReceiveState.WaitingOnInstance, retry);
                    if (bufferSuccess)
                    { 
                        if (TD.BufferOutOfOrderMessageNoInstanceIsEnabled())
                        { 
                            TD.BufferOutOfOrderMessageNoInstance(this.invoker.StaticBookmarkName); 
                        }
 
                        shouldAbandon = false;
                    }
                }
            } 

            static bool HandleEndGetInstance(IAsyncResult result) 
            { 
                ControlOperationAsyncResult thisPtr = (ControlOperationAsyncResult)result.AsyncState;
 
                bool shouldAbandon = true;
                try
                {
                    try 
                    {
                        thisPtr.workflowServiceInstance = thisPtr.invoker.instanceManager.EndGetInstance(result); 
                        shouldAbandon = false; 
                    }
                    catch (InstanceLockedException exception) 
                    {
                        RedirectionException redirectionException;
                        if (thisPtr.TryCreateRedirectionException(exception, out redirectionException))
                        { 
                            throw FxTrace.Exception.AsError(redirectionException);
                        } 
                        throw FxTrace.Exception.AsError(CreateFaultException(exception)); 
                    }
                    catch (OperationCanceledException exception) 
                    {
                        thisPtr.BufferReceiveHelper(ref shouldAbandon, true);
                        throw FxTrace.Exception.AsError(new RetryException(null, exception));
                    } 
                    catch (InstancePersistenceException exception)
                    { 
                        thisPtr.BufferReceiveHelper(ref shouldAbandon, false); 

                        if (exception is InstanceKeyNotReadyException) 
                        {
                            thisPtr.invoker.host.RaiseUnknownMessageReceived(thisPtr.operationContext.IncomingMessage);
                        }
 
                        thisPtr.invoker.host.FaultServiceHostIfNecessary(exception);
 
                        throw FxTrace.Exception.AsError(CreateFaultException(exception)); 
                    }
                } 
                catch (Exception exception)
                {
                    if (Fx.IsFatal(exception))
                    { 
                        throw;
                    } 
                    if (!shouldAbandon || !thisPtr.ShouldAbandonReceiveContext()) 
                    {
                        throw; 
                    }
                    return thisPtr.AbandonReceiveContext(exception);
                }
 
                // When creating a new instance for a normal, keyless app message, create a key for use by context exchange.
                if (!thisPtr.instanceKey.IsValid && thisPtr.instanceId == Guid.Empty) 
                { 
                    ContextMessageProperty outgoingContextMessageProperty = null;
 
                    if (!ContextMessageProperty.TryGet(thisPtr.operationContext.OutgoingMessageProperties, out outgoingContextMessageProperty))
                    {
                        outgoingContextMessageProperty = new ContextMessageProperty();
                        outgoingContextMessageProperty.Context.Add(ContextMessageProperty.InstanceIdKey, Guid.NewGuid().ToString()); 
                        outgoingContextMessageProperty.AddOrReplaceInMessageProperties(thisPtr.operationContext.OutgoingMessageProperties);
                    } 
                    else 
                    {
                        outgoingContextMessageProperty.Context[ContextMessageProperty.InstanceIdKey] = Guid.NewGuid().ToString(); 
                    }
                }
                return thisPtr.PerformOperation();
            } 

            bool PerformOperation() 
            { 
                IAsyncResult result = null;
                bool completed = false; 

                if (this.invoker.isControlOperation)
                {
                    //Mode 1: Dispatch directly to WorkflowServiceInstance method. 
                    switch (this.invoker.operationName)
                    { 
                        case XD2.WorkflowInstanceManagementService.Suspend: 
                        case XD2.WorkflowInstanceManagementService.TransactedSuspend:
                            result = this.workflowServiceInstance.BeginSuspend(false, (string)this.inputs[1] ?? SR.DefaultSuspendReason, 
                                this.transaction, this.timeoutHelper.RemainingTime(),
                                this.PrepareAsyncCompletion(handleEndOperation), this);
                            break;
                        case XD2.WorkflowInstanceManagementService.Unsuspend: 
                        case XD2.WorkflowInstanceManagementService.TransactedUnsuspend:
                            result = this.workflowServiceInstance.BeginUnsuspend(this.transaction, this.timeoutHelper.RemainingTime(), 
                                this.PrepareAsyncCompletion(handleEndOperation), this); 
                            break;
                        case XD2.WorkflowInstanceManagementService.Terminate: 
                        case XD2.WorkflowInstanceManagementService.TransactedTerminate:
                            result = this.workflowServiceInstance.BeginTerminate((string)this.inputs[1] ?? SR.DefaultTerminationReason,
                                this.transaction, this.timeoutHelper.RemainingTime(),
                                this.PrepareAsyncCompletion(handleEndOperation), this); 
                            break;
                        case XD2.WorkflowInstanceManagementService.Run: 
                        case XD2.WorkflowInstanceManagementService.TransactedRun: 
                            result = this.workflowServiceInstance.BeginRun(this.transaction, this.timeoutHelper.RemainingTime(),
                                this.PrepareAsyncCompletion(handleEndOperation), this); 
                            break;
                        case XD2.WorkflowInstanceManagementService.Cancel:
                        case XD2.WorkflowInstanceManagementService.TransactedCancel:
                            result = this.workflowServiceInstance.BeginCancel(this.transaction, 
                                this.timeoutHelper.RemainingTime(), this.PrepareAsyncCompletion(handleEndOperation), this);
                            break; 
                        case XD2.WorkflowInstanceManagementService.Abandon: 
                            string reason = (string)this.inputs[1];
                            result = this.workflowServiceInstance.BeginAbandon( 
                                new WorkflowApplicationAbortedException(!String.IsNullOrEmpty(reason) ? reason : SR.DefaultAbortReason),
                                this.timeoutHelper.RemainingTime(), this.PrepareAsyncCompletion(handleEndOperation), this);
                            break;
                        default: 
                            throw Fx.AssertAndThrow("Unreachable code");
 
                    } 
                    if (this.notification != null)
                    { 
                        this.notification.NotifyInvokeReceived();
                    }
                }
                else if (this.getInstanceContext.WorkflowCreationContext != null) 
                {
                    result = BeginRunAndGetResponse(timeoutHelper, this.PrepareAsyncCompletion(handleEndOperation), this); 
                    if (this.notification != null) 
                    {
                        this.notification.NotifyInvokeReceived(); 
                    }
                }
                else
                { 
                    try
                    { 
                        //User Endpoint operation. 
                        result = this.invoker.OnBeginServiceOperation(this.workflowServiceInstance, this.operationContext,
                            this.inputs, this.transaction, this.notification, this.timeoutHelper.RemainingTime(), 
                            this.PrepareAsyncCompletion(handleEndOperation), this);
                    }
                    catch (FaultException)
                    { 
                        throw; // ReceiveContext was handled appropriately by WorkflowOperationContext
                    } 
                    catch (Exception exception) 
                    {
                        if (Fx.IsFatal(exception)) 
                        {
                            throw;
                        }
                        if (!ShouldAbandonReceiveContext()) 
                        {
                            throw; 
                        } 
                        return AbandonReceiveContext(exception);
                    } 
                }

                if (result != null && result.CompletedSynchronously)
                { 
                    completed = HandleEndOperation(result);
                } 
 
                return completed;
            } 

            static bool HandleEndOperation(IAsyncResult result)
            {
                ControlOperationAsyncResult thisPtr = (ControlOperationAsyncResult)result.AsyncState; 

                if (thisPtr.invoker.isControlOperation) 
                { 
                    switch (thisPtr.invoker.operationName)
                    { 
                        case XD2.WorkflowInstanceManagementService.Suspend:
                        case XD2.WorkflowInstanceManagementService.TransactedSuspend:
                            thisPtr.workflowServiceInstance.EndSuspend(result);
                            break; 
                        case XD2.WorkflowInstanceManagementService.Unsuspend:
                        case XD2.WorkflowInstanceManagementService.TransactedUnsuspend: 
                            thisPtr.workflowServiceInstance.EndUnsuspend(result); 
                            break;
                        case XD2.WorkflowInstanceManagementService.Terminate: 
                        case XD2.WorkflowInstanceManagementService.TransactedTerminate:
                            thisPtr.workflowServiceInstance.EndTerminate(result);
                            break;
                        case XD2.WorkflowInstanceManagementService.Run: 
                        case XD2.WorkflowInstanceManagementService.TransactedRun:
                            thisPtr.workflowServiceInstance.EndRun(result); 
                            break; 
                        case XD2.WorkflowInstanceManagementService.Cancel:
                        case XD2.WorkflowInstanceManagementService.TransactedCancel: 
                            thisPtr.workflowServiceInstance.EndCancel(result);
                            break;
                        case XD2.WorkflowInstanceManagementService.Abandon:
                            thisPtr.workflowServiceInstance.EndAbandon(result); 
                            break;
                        default: 
                            throw Fx.AssertAndThrow("Unreachable code"); 
                    }
                } 
                else if (thisPtr.getInstanceContext.WorkflowCreationContext != null)
                {
                    thisPtr.returnValue = thisPtr.EndRunAndGetResponse(result, out thisPtr.outputs);
                } 
                else
                { 
                    //User operation 
                    try
                    { 
                        thisPtr.returnValue = thisPtr.invoker.OnEndServiceOperation(thisPtr.workflowServiceInstance, out thisPtr.outputs, result);
                    }
                    catch (FaultException)
                    { 
                        throw; // ReceiveContext was handled appropriately by WorkflowOperationContext
                    } 
                    catch (Exception exception) 
                    {
                        if (Fx.IsFatal(exception)) 
                        {
                            throw;
                        }
                        if (!thisPtr.ShouldAbandonReceiveContext()) 
                        {
                            throw; 
                        } 
                        return thisPtr.AbandonReceiveContext(exception);
                    } 
                }

                return true;
            } 

            bool ShouldAbandonReceiveContext() 
            { 
                return this.receiveContext != null && this.receiveContext.State != ReceiveContextState.Faulted;
            } 

            bool AbandonReceiveContext(Exception operationException)
            {
                Fx.Assert(ShouldAbandonReceiveContext(), "ShouldAbandonReceiveContext() is false!"); 
                if (handleEndAbandonReceiveContext == null)
                { 
                    handleEndAbandonReceiveContext = new AsyncCompletion(HandleEndAbandonReceiveContext); 
                }
 
                Fx.Assert(operationException != null, "operationException must not be null!");
                Fx.Assert(this.operationException == null, "AbandonReceiveContext must not be called twice!");
                this.operationException = operationException;
                IAsyncResult result = this.receiveContext.BeginAbandon(TimeSpan.MaxValue, this.PrepareAsyncCompletion(handleEndAbandonReceiveContext), this); 
                return SyncContinue(result);
            } 
 
            static bool HandleEndAbandonReceiveContext(IAsyncResult result)
            { 
                ControlOperationAsyncResult thisPtr = (ControlOperationAsyncResult)result.AsyncState;
                thisPtr.receiveContext.EndAbandon(result);
                throw FxTrace.Exception.AsError(thisPtr.operationException);
            } 

            void EnsureInstanceId() 
            { 
                if (this.invoker.isControlOperation)
                { 
                    switch (this.invoker.operationName)
                    {
                        case XD2.WorkflowInstanceManagementService.Abandon:
                        case XD2.WorkflowInstanceManagementService.Cancel: 
                        case XD2.WorkflowInstanceManagementService.TransactedCancel:
                        case XD2.WorkflowInstanceManagementService.Run: 
                        case XD2.WorkflowInstanceManagementService.TransactedRun: 
                        case XD2.WorkflowInstanceManagementService.Suspend:
                        case XD2.WorkflowInstanceManagementService.TransactedSuspend: 
                        case XD2.WorkflowInstanceManagementService.Terminate:
                        case XD2.WorkflowInstanceManagementService.TransactedTerminate:
                        case XD2.WorkflowInstanceManagementService.Unsuspend:
                        case XD2.WorkflowInstanceManagementService.TransactedUnsuspend: 
                            this.instanceId = GetInstanceIdForControlOperation(this.inputs);
                            break; 
                        default: 
                            throw Fx.AssertAndThrow("Unreachable code");
                    } 
                }
                else if (this.invoker.endpoint is WorkflowHostingEndpoint)
                {
                    WorkflowHostingEndpoint hostingEndpoint = (WorkflowHostingEndpoint)this.invoker.endpoint; 
                    this.instanceId = hostingEndpoint.OnGetInstanceId(inputs, this.operationContext);
                    if (this.instanceId == Guid.Empty) 
                    { 
                        this.invoker.GetInstanceKeys(this.operationContext, out this.instanceKey, out this.additionalKeys);
                    } 
                }
                else
                {
                    //User endpoint operation. 
                    this.invoker.GetInstanceKeys(this.operationContext, out this.instanceKey, out this.additionalKeys);
                } 
            } 

            Guid GetInstanceIdForControlOperation(object[] args) 
            {
                Fx.Assert(args != null && args.Length > 0, "Cannot get argument");
                object arg = args[0];
 
                if (arg != null && arg is Guid)
                { 
                    return (Guid)arg; 
                }
                else 
                {
                    throw FxTrace.Exception.AsError(new InvalidOperationException(SR.FailedToGetInstanceIdForControlOperation));
                }
            } 

            bool TryCreateRedirectionException(InstanceLockedException exception, out RedirectionException redirectionException) 
            { 
                Uri redirectVia = null;
 
                object redirectViaObject;
                string endpointName = this.invoker.endpoint != null ? this.invoker.endpoint.Name : null;
                XName endpointXName = endpointName == null ? null : WorkflowServiceNamespace.EndpointsPath.GetName(endpointName);
                if (endpointXName != null && exception.SerializableInstanceOwnerMetadata != null && 
                    exception.SerializableInstanceOwnerMetadata.TryGetValue(endpointXName, out redirectViaObject))
                { 
                    redirectVia = redirectViaObject as Uri; 
                }
 
                if (redirectVia == null)
                {
                    redirectionException = null;
                    return false; 
                }
 
                redirectionException = new RedirectionException(RedirectionType.Resource, RedirectionDuration.Permanent, 
                    RedirectionScope.Session, new RedirectionLocation(redirectVia));
                return true; 
            }

            static FaultException CreateFaultException(InstancePersistenceException exception)
            { 
                return new FaultException(OperationExecutionFault.CreateInstanceNotFoundFault(exception.Message));
            } 
 
            IAsyncResult BeginRunAndGetResponse(TimeoutHelper timeoutHelper, AsyncCallback callback, object state)
            { 
                return RunAndGetResponseAsyncResult.Create(this, timeoutHelper, callback, state);
            }

            object EndRunAndGetResponse(IAsyncResult result, out object[] outputs) 
            {
                return RunAndGetResponseAsyncResult.End(result, out outputs); 
            } 

            class RunAndGetResponseAsyncResult : AsyncResult 
            {
                static AsyncCompletion handleEndRun = new AsyncCompletion(HandleEndRun);
                static AsyncCompletion handleEndSuspend = new AsyncCompletion(HandleEndSuspend);
                static AsyncCompletion handleEndGetResponse = new AsyncCompletion(HandleEndGetResponse); 

                ControlOperationAsyncResult control; 
                TimeoutHelper timeoutHelper; 
                object returnValue;
                object[] outputs; 

                RunAndGetResponseAsyncResult(ControlOperationAsyncResult control, TimeoutHelper timeoutHelper, AsyncCallback callback, object state)
                    : base(callback, state)
                { 
                    this.control = control;
                    this.timeoutHelper = timeoutHelper; 
 
                    bool completeSelf = true;
 
                    if (control.getInstanceContext.WorkflowCreationContext.CreateOnly)
                    {
                        completeSelf = Suspend();
                    } 
                    else
                    { 
                        completeSelf = Run(); 
                    }
 
                    if (completeSelf)
                    {
                        Complete(true);
                    } 
                }
 
                public static RunAndGetResponseAsyncResult Create(ControlOperationAsyncResult control, TimeoutHelper timeoutHelper, AsyncCallback callback, object state) 
                {
                    return new RunAndGetResponseAsyncResult(control, timeoutHelper, callback, state); 
                }

                public static object End(IAsyncResult result, out object[] outputs)
                { 
                    RunAndGetResponseAsyncResult thisPtr = AsyncResult.End(result);
                    outputs = thisPtr.outputs; 
                    return thisPtr.returnValue; 
                }
 
                bool Run()
                {
                    IAsyncResult result = this.control.workflowServiceInstance.BeginRun(this.control.transaction, this.timeoutHelper.RemainingTime(),
                        PrepareAsyncCompletion(handleEndRun), this); 
                    return SyncContinue(result);
                } 
 
                static bool HandleEndRun(IAsyncResult result)
                { 
                    RunAndGetResponseAsyncResult thisPtr = (RunAndGetResponseAsyncResult)result.AsyncState;
                    thisPtr.control.workflowServiceInstance.EndRun(result);
                    return thisPtr.GetResponse();
                } 

                bool Suspend() 
                { 
                    IAsyncResult result = this.control.workflowServiceInstance.BeginSuspend(false, SR.DefaultCreateOnlyReason,
                        this.control.transaction, this.timeoutHelper.RemainingTime(), PrepareAsyncCompletion(handleEndSuspend), this); 
                    return SyncContinue(result);
                }

                static bool HandleEndSuspend(IAsyncResult result) 
                {
                    RunAndGetResponseAsyncResult thisPtr = (RunAndGetResponseAsyncResult)result.AsyncState; 
                    thisPtr.control.workflowServiceInstance.EndSuspend(result); 
                    return thisPtr.GetResponse();
                } 

                bool GetResponse()
                {
                    IAsyncResult result = this.control.getInstanceContext.WorkflowHostingResponseContext.BeginGetResponse(this.timeoutHelper.RemainingTime(), 
                        PrepareAsyncCompletion(handleEndGetResponse), this);
                    return SyncContinue(result); 
                } 

                static bool HandleEndGetResponse(IAsyncResult result) 
                {
                    RunAndGetResponseAsyncResult thisPtr = (RunAndGetResponseAsyncResult)result.AsyncState;
                    thisPtr.returnValue = thisPtr.control.getInstanceContext.WorkflowHostingResponseContext.EndGetResponse(result, out thisPtr.outputs);
                    return true; 
                }
            } 
        } 

        //AsyncResult implementation for User endpoint operation dispatch. 
        class ServiceOperationAsyncResult : AsyncResult
        {
            static AsyncCompletion handleEndInvoke = new AsyncCompletion(HandleEndInvoke);
            IOperationInvoker innerInvoker; 
            WorkflowServiceInstance durableInstance;
            object[] inputs; 
            OperationContext operationContext; 
            object returnValue;
            object[] outputs; 
            Transaction currentTransaction;
            IInvokeReceivedNotification notification;

            public ServiceOperationAsyncResult(IOperationInvoker innerInvoker, WorkflowServiceInstance durableInstance, 
                object[] inputs, OperationContext operationContext, Transaction currentTransaction, IInvokeReceivedNotification notification,
                AsyncCallback callback, object state) 
                : base(callback, state) 
            {
                this.durableInstance = durableInstance; 
                this.operationContext = operationContext;
                this.inputs = inputs;
                this.innerInvoker = innerInvoker;
                this.currentTransaction = currentTransaction; 
                this.notification = notification;
 
                if (innerInvoker == null) 
                {
                    //Mode2: Derived invoker should have handled this call. 
                    throw Fx.AssertAndThrow("Cannot reach this path without innerInvoker");
                }

                if (this.innerInvoker.IsSynchronous) 
                {
                    TransactionScope scope = Fx.CreateTransactionScope(this.currentTransaction); 
                    try 
                    {
                        using (new OperationContextScopeHelper(this.operationContext)) 
                        {
                            IManualConcurrencyOperationInvoker manualInvoker = this.innerInvoker as IManualConcurrencyOperationInvoker;
                            if (manualInvoker != null)
                            { 
                                this.returnValue = manualInvoker.Invoke(this.durableInstance, this.inputs, this.notification, out this.outputs);
                            } 
                            else 
                            {
                                this.returnValue = this.innerInvoker.Invoke(this.durableInstance, this.inputs, out this.outputs); 
                            }
                        }
                    }
                    finally 
                    {
                        Fx.CompleteTransactionScope(ref scope); 
                    } 
                    this.Complete(true);
                } 
                else
                {
                    IAsyncResult result;
                    using (PrepareTransactionalCall(this.currentTransaction)) 
                    {
                        using (new OperationContextScopeHelper(this.operationContext)) 
                        { 
                            IManualConcurrencyOperationInvoker manualInvoker = this.innerInvoker as IManualConcurrencyOperationInvoker;
                            if (manualInvoker != null) 
                            {
                                result = manualInvoker.InvokeBegin(this.durableInstance, this.inputs, this.notification, this.PrepareAsyncCompletion(handleEndInvoke), this);
                            }
                            else 
                            {
                                result = this.innerInvoker.InvokeBegin(this.durableInstance, this.inputs, this.PrepareAsyncCompletion(handleEndInvoke), this); 
                            } 
                        }
                    } 
                    if (SyncContinue(result))
                    {
                        this.Complete(true);
                    } 
                }
            } 
 
            public static object End(out object[] outputs, IAsyncResult result)
            { 
                ServiceOperationAsyncResult thisPtr = AsyncResult.End(result);
                outputs = thisPtr.outputs;
                return thisPtr.returnValue;
            } 

            static bool HandleEndInvoke(IAsyncResult result) 
            { 
                ServiceOperationAsyncResult thisPtr = (ServiceOperationAsyncResult)result.AsyncState;
 
                TransactionScope scope = Fx.CreateTransactionScope(thisPtr.currentTransaction);
                try
                {
                    using (new OperationContextScopeHelper(thisPtr.operationContext)) 
                    {
                        thisPtr.returnValue = thisPtr.innerInvoker.InvokeEnd(thisPtr.durableInstance, out thisPtr.outputs, result); 
                        return true; 
                    }
                } 
                finally
                {
                    Fx.CompleteTransactionScope(ref scope);
                } 
            }
 
            class OperationContextScopeHelper : IDisposable 
            {
                OperationContext current; 

                public OperationContextScopeHelper(OperationContext newContext)
                {
                    this.current = OperationContext.Current; 
                    OperationContext.Current = newContext;
                } 
 
                void IDisposable.Dispose()
                { 
                    OperationContext.Current = this.current;
                }
            }
        } 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.


                        

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