File: System\ServiceModel\Dispatcher\ServiceOperationInvoker.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;
    using System.Diagnostics.CodeAnalysis;
    using System.Runtime;
    using System.ServiceModel.Description;
    using System.ServiceModel.Diagnostics;
 
    class ServiceOperationInvoker : IOperationInvoker
    {
        bool canCreateInstance;
        bool completesInstance;
        bool contractCausesSave;
        IOperationInvoker innerInvoker;
 
        public ServiceOperationInvoker(IOperationInvoker innerInvoker, bool completesInstance, bool canCreateInstance, bool contractCausesSave)
        {
            if (innerInvoker == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("innerInvoker");
            }
 
            this.innerInvoker = innerInvoker;
            this.completesInstance = completesInstance;
            this.canCreateInstance = canCreateInstance;
            this.contractCausesSave = contractCausesSave;
        }
 
        public bool IsSynchronous
        {
            get { return this.innerInvoker.IsSynchronous; }
        }
 
        public object[] AllocateInputs()
        {
            return this.innerInvoker.AllocateInputs();
        }
 
        public object Invoke(object instance, object[] inputs, out object[] outputs)
        {
            if (instance == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("instance");
            }
 
            ServiceDurableInstance durableInstance = instance as ServiceDurableInstance;
 
            if (durableInstance == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                    new InvalidOperationException(
                    SR2.GetString(SR2.InvokeCalledWithWrongType, typeof(DurableServiceAttribute).Name)));
            }
 
            object serviceInstance = durableInstance.StartOperation(this.canCreateInstance);
            Exception operationException = null;
 
            bool failFast = false;
            try
            {
                return this.innerInvoker.Invoke(serviceInstance, inputs, out outputs);
            }
            catch (Exception e)
            {
                if (Fx.IsFatal(e))
                {
                    failFast = true;
                    throw;
                }
 
                operationException = e;
                ServiceErrorHandler.MarkException(e);
                throw;
            }
            finally
            {
                if (!failFast)
                {
                    durableInstance.FinishOperation(this.completesInstance, this.contractCausesSave, operationException);
                }
            }
        }
 
        public IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state)
        {
            if (instance == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("instance");
            }
 
            ServiceDurableInstance durableInstance = instance as ServiceDurableInstance;
 
            if (durableInstance == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                    new InvalidOperationException(
                    SR2.GetString(SR2.InvokeCalledWithWrongType, typeof(DurableServiceAttribute).Name)));
            }
 
            return new InvokeAsyncResult(durableInstance, inputs, this, this.canCreateInstance, callback, state);
        }
 
        public object InvokeEnd(object instance, out object[] outputs, IAsyncResult result)
        {
            return InvokeAsyncResult.End(out outputs, result);
        }
 
        public class InvokeAsyncResult : AsyncResult
        {
            static AsyncCallback finishCallback = Fx.ThunkCallback(new AsyncCallback(FinishComplete));
            static AsyncCallback invokeCallback = Fx.ThunkCallback(new AsyncCallback(InvokeComplete));
            static AsyncCallback startCallback = Fx.ThunkCallback(new AsyncCallback(StartComplete));
            Exception completionException;
            ServiceDurableInstance durableInstance;
            object[] inputs;
 
            ServiceOperationInvoker invoker;
            OperationContext operationContext;
            object[] outputs;
            object returnValue;
            object serviceInstance;
 
            public InvokeAsyncResult(ServiceDurableInstance instance, object[] inputs, ServiceOperationInvoker invoker, bool canCreateInstance, AsyncCallback callback, object state)
                : base(callback, state)
            {
                this.invoker = invoker;
                this.inputs = inputs;
                this.durableInstance = instance;
                this.operationContext = OperationContext.Current;
 
                IAsyncResult result = this.durableInstance.BeginStartOperation(canCreateInstance, startCallback, this);
 
                if (result.CompletedSynchronously)
                {
                    this.serviceInstance = this.durableInstance.EndStartOperation(result);
                    if (DoInvoke())
                    {
                        Complete(true, this.completionException);
                    }
                }
            }
 
            public static object End(out object[] outputs, IAsyncResult result)
            {
                InvokeAsyncResult invokeResult = AsyncResult.End<InvokeAsyncResult>(result);
 
                outputs = invokeResult.outputs;
 
                return invokeResult.returnValue;
            }
 
            // We pass the exception to another thread
            [SuppressMessage("Reliability", "Reliability104")]
            [SuppressMessage("Microsoft.Design", "CA1031")]
            static void FinishComplete(IAsyncResult result)
            {
                if (result.CompletedSynchronously)
                {
                    return;
                }
 
                InvokeAsyncResult invokeResult = result.AsyncState as InvokeAsyncResult;
                Fx.Assert(invokeResult != null, "Async state should have been of type InvokeAsyncResult.");
 
                try
                {
                    invokeResult.durableInstance.EndFinishOperation(result);
                }
                catch (Exception e)
                {
                    if (Fx.IsFatal(e))
                    {
                        throw;
                    }
 
                    invokeResult.completionException = e;
                }
 
                invokeResult.Complete(false, invokeResult.completionException);
            }
 
            // We pass the exception to another thread
            [SuppressMessage("Reliability", "Reliability104")]
            [SuppressMessage("Microsoft.Design", "CA1031")]
            static void InvokeComplete(IAsyncResult resultParameter)
            {
                if (resultParameter.CompletedSynchronously)
                {
                    return;
                }
 
                InvokeAsyncResult invokeResult = resultParameter.AsyncState as InvokeAsyncResult;
 
                Fx.Assert(invokeResult != null,
                    "Async state should have been of type InvokeAsyncResult.");
 
                try
                {
                    invokeResult.returnValue = invokeResult.invoker.innerInvoker.InvokeEnd(invokeResult.serviceInstance, out invokeResult.outputs, resultParameter);
                }
                catch (Exception e)
                {
                    if (Fx.IsFatal(e))
                    {
                        throw;
                    }
 
                    ServiceErrorHandler.MarkException(e);
                    invokeResult.completionException = e;
                }
                finally
                {
                    if (invokeResult.DoFinish())
                    {
                        invokeResult.Complete(false, invokeResult.completionException);
                    }
                }
            }
 
            // We pass the exception to another thread
            [SuppressMessage("Reliability", "Reliability104")]
            [SuppressMessage("Microsoft.Design", "CA1031")]
            static void StartComplete(IAsyncResult resultParameter)
            {
                if (resultParameter.CompletedSynchronously)
                {
                    return;
                }
 
                InvokeAsyncResult invokeResult = resultParameter.AsyncState as InvokeAsyncResult;
 
                Fx.Assert(invokeResult != null,
                    "Async state should have been of type InvokeAsyncResult.");
 
                try
                {
                    invokeResult.serviceInstance = invokeResult.durableInstance.EndStartOperation(resultParameter);
                }
                catch (Exception e)
                {
                    if (Fx.IsFatal(e))
                    {
                        throw;
                    }
 
                    invokeResult.Complete(false, e);
                    return;
                }
 
                if (invokeResult.DoInvoke())
                {
                    invokeResult.Complete(false, invokeResult.completionException);
                }
            }
 
            // We pass the exception to another thread
            [SuppressMessage("Reliability", "Reliability104")]
            [SuppressMessage("Microsoft.Design", "CA1031")]
            bool DoFinish()
            {
                try
                {
                    IAsyncResult result = this.durableInstance.BeginFinishOperation(this.invoker.completesInstance, this.invoker.contractCausesSave, this.completionException, finishCallback, this);
 
                    if (result.CompletedSynchronously)
                    {
                        this.durableInstance.EndFinishOperation(result);
                        return true;
                    }
                }
                catch (Exception e)
                {
                    if (Fx.IsFatal(e))
                    {
                        throw;
                    }
 
                    this.completionException = e;
                    return true;
                }
 
                return false;
            }
 
            // We pass the exception to another thread
            [SuppressMessage("Reliability", "Reliability104")]
            [SuppressMessage("Microsoft.Design", "CA1031")]
            bool DoInvoke()
            {
                bool finishNow = false;
 
                try
                {
                    IAsyncResult result = null;
 
                    using (OperationContextScope operationScope = new OperationContextScope(this.operationContext))
                    {
                        result = this.invoker.innerInvoker.InvokeBegin(this.serviceInstance, this.inputs, invokeCallback, this);
                    }
 
                    if (result.CompletedSynchronously)
                    {
                        this.returnValue = this.invoker.innerInvoker.InvokeEnd(this.serviceInstance, out this.outputs, result);
                        finishNow = true;
                    }
                }
                catch (Exception e)
                {
                    if (Fx.IsFatal(e))
                    {
                        throw;
                    }
 
                    ServiceErrorHandler.MarkException(e);
                    this.completionException = e;
                    finishNow = true;
                }
 
                if (finishNow)
                {
                    if (DoFinish())
                    {
                        return true;
                    }
                }
 
                return false;
            }
        }
    }
}