WorkflowOperationContext.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 / WorkflowOperationContext.cs / 1407647 / WorkflowOperationContext.cs

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

namespace System.ServiceModel.Activities 
{
    using System.Activities; 
    using System.Collections.Generic; 
    using System.Diagnostics;
    using System.Runtime; 
    using System.Runtime.Diagnostics;
    using System.Security;
    using System.ServiceModel.Activation;
    using System.ServiceModel.Activities.Description; 
    using System.ServiceModel.Activities.Dispatcher;
    using System.ServiceModel.Channels; 
    using System.ServiceModel.Diagnostics; 
    using System.ServiceModel.Dispatcher;
    using System.Transactions; 
    using TD2 = System.ServiceModel.Diagnostics.Application.TD;

    // This AsyncResult completion is very tricky. It can complete in two path.
    // FastPath: When workflow executes synchronously(SendFault/SendReply called before ResumeBookmark completes) we complete the AsyncResult at HandleEndResumeBookmark; 
    // Async Path: If workflow goes async (SendFault/SendReply called after ResumeBookmark completes) we complete the AsyncResult at SendFault/SendReply.
    class WorkflowOperationContext : AsyncResult 
    { 
        static readonly ReadOnlyDictionary emptyDictionary = new ReadOnlyDictionary(new Dictionary(), false);
        static readonly object[] emptyObjectArray = new object[0]; 
        static AsyncCompletion handleEndResumeBookmark = new AsyncCompletion(HandleEndResumeBookmark);
        static AsyncCompletion handleEndWaitForPendingOperations = new AsyncCompletion(HandleEndWaitForPendingOperations);
        static AsyncCompletion handleEndProcessReceiveContext;
        static Action onCompleting = new Action(Finally); 

        object[] inputs; 
        string operationName; 
        object[] outputs;
        object operationReturnValue; 
        object thisLock;

        WorkflowServiceInstance workflowInstance;
        Bookmark bookmark; 
        object bookmarkValue;
        BookmarkScope bookmarkScope; 
 
        IInvokeReceivedNotification notification;
        IAsyncResult pendingAsyncResult; 

        TimeoutHelper timeoutHelper;
        Exception pendingException;
 
        ReceiveContext receiveContext;
 
        // perf counter data 
        bool performanceCountersEnabled;
        long beginTime; 

        // tracing data
        bool propagateActivity;
        Guid ambientActivityId; 
        Guid e2eActivityId;
        long beginOperation; 
 
        //Tracking for decrement of ASP.NET busy count
        bool hasDecrementedBusyCount; 

        WorkflowOperationContext(object[] inputs, OperationContext operationContext, string operationName,
            bool performanceCountersEnabled, bool propagateActivity, Transaction currentTransaction,
            WorkflowServiceInstance workflowInstance, IInvokeReceivedNotification notification, WorkflowOperationBehavior behavior, 
            TimeSpan timeout, AsyncCallback callback, object state)
            : base(callback, state) 
        { 
            this.inputs = inputs;
            this.operationName = operationName; 
            this.OperationContext = operationContext;
            this.CurrentTransaction = currentTransaction;
            this.performanceCountersEnabled = performanceCountersEnabled;
            this.propagateActivity = propagateActivity; 
            this.timeoutHelper = new TimeoutHelper(timeout);
            this.workflowInstance = workflowInstance; 
            this.thisLock = new object(); 
            this.notification = notification;
            this.OnCompleting = onCompleting; 

            // Resolve bookmark
            Fx.Assert(behavior != null, "behavior must not be null!");
            this.bookmark = behavior.OnResolveBookmark(this, out this.bookmarkScope, out this.bookmarkValue); 
            Fx.Assert(this.bookmark != null, "bookmark must not be null!");
 
            bool completeSelf = false; 

            try 
            {
                // set activity ID on the executing thread (Bug 113386)
                if (TraceUtility.MessageFlowTracingOnly)
                { 
                    this.e2eActivityId = TraceUtility.GetReceivedActivityId(this.OperationContext);
                    DiagnosticTrace.ActivityId = this.e2eActivityId; 
                } 

                // Take ownership of the ReceiveContext when buffering is enabled by removing the property 
                if (this.workflowInstance.BufferedReceiveManager != null)
                {
                    if (!ReceiveContext.TryGet(this.OperationContext.IncomingMessageProperties, out this.receiveContext))
                    { 
                        Fx.Assert("ReceiveContext expected when BufferedReceives are enabled");
                    } 
 
                    this.OperationContext.IncomingMessageProperties.Remove(ReceiveContext.Name);
                } 

                completeSelf = ProcessRequest();
            }
            catch (Exception e) 
            {
                if (Fx.IsFatal(e)) 
                { 
                    throw;
                } 

                // Failing synchronously is one case where AsyncResult won't handle calling OnCompleting
                OnCompleting(this, e);
                throw; 
            }
 
            if (completeSelf) 
            {
                base.Complete(true); 
            }
        }

        public object[] Inputs 
        {
            get 
            { 
                return this.inputs;
            } 
        }

        public OperationContext OperationContext
        { 
            get;
            private set; 
        } 

        public Transaction CurrentTransaction 
        {
            get;
            private set;
        } 

        public object BookmarkValue 
        { 
            get
            { 
                return this.bookmarkValue;
            }
        }
 
        public bool HasResponse
        { 
            get 
            {
                lock (this.thisLock) 
                {
                    return this.CurrentState == State.Completed || this.CurrentState == State.ResultReceived;
                }
            } 
        }
 
        //Completion state of this AsyncResult guarded by propertyLock 
        State CurrentState
        { 
            get;
            set;
        }
 
        public Guid E2EActivityId
        { 
            get 
            {
                return this.e2eActivityId; 
            }
        }

        public static IAsyncResult BeginProcessRequest(WorkflowServiceInstance workflowInstance, OperationContext operationContext, string operationName, 
            object[] inputs, bool performanceCountersEnabled, bool propagateActivity, Transaction currentTransaction, IInvokeReceivedNotification notification,
            WorkflowOperationBehavior behavior, TimeSpan timeout, AsyncCallback callback, object state) 
        { 
            Fx.Assert(inputs != null, "Null inputs");
            return new WorkflowOperationContext(inputs, operationContext, operationName, performanceCountersEnabled, 
                propagateActivity, currentTransaction, workflowInstance, notification, behavior, timeout, callback, state);
        }

        public static object EndProcessRequest(IAsyncResult result, out object[] outputs) 
        {
            WorkflowOperationContext thisPtr = AsyncResult.End(result); 
            outputs = thisPtr.outputs; 
            return thisPtr.operationReturnValue;
        } 

        public void SendFault(Exception exception)
        {
            Fx.Assert(exception != null, "Null Exception"); 

            this.pendingException = exception; 
 
            bool completeNow;
 
            lock (this.thisLock)
            {
                Fx.Assert(this.CurrentState != State.Completed && this.CurrentState != State.ResultReceived, "Cannot receive this call after completion/result");
                completeNow = ProcessReply(); 
            }
 
            if (completeNow) 
            {
                this.Complete(false, exception); 
            }
        }

        public void SendReply(Message returnValue) 
        {
            bool completeNow; 
 
            lock (this.thisLock)
            { 
                Fx.Assert(this.CurrentState != State.Completed && this.CurrentState != State.ResultReceived, "Cannot receive this call after completion/result");
                this.outputs = WorkflowOperationContext.emptyObjectArray; // everything is in the Message return value for workflow
                this.operationReturnValue = returnValue;
                completeNow = ProcessReply(); 
            }
 
            if (completeNow) 
            {
                base.Complete(false); 
            }
        }

        public void SendReply(object returnValue, object[] outputs) 
        {
            bool completeNow; 
 
            lock (this.thisLock)
            { 
                Fx.Assert(this.CurrentState != State.Completed && this.CurrentState != State.ResultReceived, "Cannot receive this call after completion/result");
                this.outputs = outputs ?? WorkflowOperationContext.emptyObjectArray;
                this.operationReturnValue = returnValue;
                completeNow = ProcessReply(); 
            }
 
            if (completeNow) 
            {
                base.Complete(false); 
            }
        }

        //No-op for two-ways. 
        public void SetOperationCompleted()
        { 
            bool completeNow; 

            lock (this.thisLock) 
            {
                completeNow = ProcessReply();
            }
 
            if (completeNow)
            { 
                base.Complete(false); 
            }
        } 

        bool ProcessReply()
        {
            bool completed = false; 
            this.workflowInstance.ReleaseContext(this);
            this.RemovePendingOperation(); 
 
            if (this.CurrentState == State.BookmarkResumption) //We are still in Bookmark Resume
            { 
                this.CurrentState = State.ResultReceived; //HandleEndResumeBookmark will take care of Completing AsyncResult.
            }
            else if (this.CurrentState == State.WaitForResult) //We already finished the bookmarkOperation; Now have to signal the AsynResult.
            { 
                this.CurrentState = State.Completed;
                completed = true; 
            } 

            // we are not really completed until the ReceiveContext finishes its work 
            if (completed)
            {
                if (this.pendingException == null)
                { 
                    completed = ProcessReceiveContext();
                } 
                else 
                {
                    // if there's a pendingException, we let the RC abandon async so there's no need 
                    // to affect the completed status
                    BufferedReceiveManager.AbandonReceiveContext(this.receiveContext);
                }
            } 

            return completed; 
        } 

        void ProcessInitializationTraces() 
        {
            //Let asp.net know that it needs to wait
            IncrementBusyCount();
 
            try
            { 
                if (TraceUtility.MessageFlowTracingOnly) 
                {
                    //ensure that Activity ID is set 
                    DiagnosticTrace.ActivityId = this.E2EActivityId;
                    this.propagateActivity = false;
                }
                if (TraceUtility.ActivityTracing || (!TraceUtility.MessageFlowTracing && this.propagateActivity)) 
                {
                    this.e2eActivityId = TraceUtility.GetReceivedActivityId(this.OperationContext); 
                    if ((this.E2EActivityId != Guid.Empty) && (this.E2EActivityId != Trace.CorrelationManager.ActivityId)) 
                    {
                        this.propagateActivity = true; 
                        this.OperationContext.IncomingMessageProperties[MessagingActivityHelper.E2EActivityId] = this.E2EActivityId;
                        this.ambientActivityId = Trace.CorrelationManager.ActivityId;
                        FxTrace.Trace.SetAndTraceTransfer(this.E2EActivityId, true);
                        if (TD.StartSignpostEventIsEnabled()) 
                        {
                            TD.StartSignpostEvent(new DictionaryTraceRecord(new Dictionary(2) { 
                                                    { MessagingActivityHelper.ActivityName, MessagingActivityHelper.ActivityNameWorkflowOperationInvoke }, 
                                                    { MessagingActivityHelper.ActivityType, MessagingActivityHelper.ActivityTypeExecuteUserCode }
                            })); 
                        }
                    }
                    else
                    { 
                        this.propagateActivity = false;
                    } 
                } 
            }
            catch (Exception ex) 
            {
                if(Fx.IsFatal(ex))
                {
                    throw; 
                }
                FxTrace.Exception.AsInformation(ex); 
            } 
        }
 

        void DecrementBusyCount()
        {
            lock (this.thisLock) 
            {
                if (!this.hasDecrementedBusyCount) 
                { 
                    AspNetEnvironment.Current.DecrementBusyCount();
                    if (AspNetEnvironment.Current.TraceDecrementBusyCountIsEnabled()) 
                    {
                        AspNetEnvironment.Current.TraceDecrementBusyCount(SR.BusyCountTraceFormatString(this.workflowInstance.Id));
                    }
                    this.hasDecrementedBusyCount = true; 
                }
            } 
        } 

        void IncrementBusyCount() 
        {
            AspNetEnvironment.Current.IncrementBusyCount();
            if (AspNetEnvironment.Current.TraceIncrementBusyCountIsEnabled())
            { 
                AspNetEnvironment.Current.TraceIncrementBusyCount(SR.BusyCountTraceFormatString(this.workflowInstance.Id));
            } 
        } 

        void EmitTransferFromInstanceId() 
        {
            if (TraceUtility.MessageFlowTracing)
            {
                //set the WF instance ID as the Activity ID 
                if (DiagnosticTrace.ActivityId != this.workflowInstance.Id)
                { 
                    DiagnosticTrace.ActivityId = this.workflowInstance.Id; 
                }
                FxTrace.Trace.SetAndTraceTransfer(this.E2EActivityId, true); 
            }
        }

        void ProcessFinalizationTraces() 
        {
            try 
            { 
                if (this.propagateActivity)
                { 
                    Guid oldId = Trace.CorrelationManager.ActivityId;
                    if (TD.StopSignpostEventIsEnabled())
                    {
                        TD.StopSignpostEvent(new DictionaryTraceRecord(new Dictionary(2) { 
                                                    { MessagingActivityHelper.ActivityName, MessagingActivityHelper.ActivityNameWorkflowOperationInvoke },
                                                    { MessagingActivityHelper.ActivityType, MessagingActivityHelper.ActivityTypeExecuteUserCode } 
                        })); 
                    }
                    FxTrace.Trace.SetAndTraceTransfer(this.ambientActivityId, true); 
                    this.ambientActivityId = Guid.Empty;
                }
            }
            catch (Exception ex) 
            {
                if (Fx.IsFatal(ex)) 
                { 
                    throw;
                } 
                FxTrace.Exception.AsInformation(ex);
            }
            DecrementBusyCount();
        } 

        //Perf counter helpers. 
        void TrackMethodCalled() 
        {
            if (this.performanceCountersEnabled) 
            {
                using (new OperationContextScopeHelper(this.OperationContext))
                {
                    PerformanceCounters.MethodCalled(this.operationName); 
                }
 
                try 
                {
                    if (System.Runtime.Interop.UnsafeNativeMethods.QueryPerformanceCounter(out this.beginTime) == 0) 
                    {
                        this.beginTime = -1;
                    }
                } 
                catch (SecurityException securityException)
                { 
                    throw FxTrace.Exception.AsError(new SecurityException(SR.PartialTrustPerformanceCounterNotEnabled, securityException)); 
                }
            } 

            if (TD2.OperationCompletedIsEnabled() ||
                    TD2.OperationFaultedIsEnabled() ||
                    TD2.OperationFailedIsEnabled()) 
            {
                this.beginOperation = DateTime.UtcNow.Ticks; 
            } 

            if (TD2.OperationInvokedIsEnabled()) 
            {
                using (new OperationContextScopeHelper(this.OperationContext))
                {
                    TD2.OperationInvoked(this.operationName, TraceUtility.GetCallerInfo(this.OperationContext)); 
                }
            } 
        } 

        void TrackMethodFaulted() 
        {
            if (this.performanceCountersEnabled)
            {
                long duration = this.GetDuration(); 
                using (new OperationContextScopeHelper(this.OperationContext))
                { 
                    PerformanceCounters.MethodReturnedFault(this.operationName, duration); 
                }
            } 
            if (TD2.OperationFaultedIsEnabled())
            {
                using (new OperationContextScopeHelper(this.OperationContext))
                { 
                    TD2.OperationFaulted(this.operationName,
                        TraceUtility.GetUtcBasedDurationForTrace(this.beginOperation)); 
                } 
            }
        } 

        void TrackMethodFailed()
        {
            if (this.performanceCountersEnabled) 
            {
                long duration = this.GetDuration(); 
                using (new OperationContextScopeHelper(this.OperationContext)) 
                {
                    PerformanceCounters.MethodReturnedError(this.operationName, duration); 
                }
            }
            if (TD2.OperationFailedIsEnabled())
            { 
                using (new OperationContextScopeHelper(this.OperationContext))
                { 
                    TD2.OperationFailed(this.operationName, 
                        TraceUtility.GetUtcBasedDurationForTrace(this.beginOperation));
                } 
            }
        }

        long GetDuration() 
        {
            long currentTime = 0; 
            long duration = 0; 

            if ((this.beginTime >= 0) && 
                (System.Runtime.Interop.UnsafeNativeMethods.QueryPerformanceCounter(out currentTime) != 0))
            {
                duration = currentTime - this.beginTime;
            } 
            return duration;
        } 
 

        void TrackMethodSucceeded() 
        {
            if (this.performanceCountersEnabled)
            {
                long duration = this.GetDuration(); 
                using (new OperationContextScopeHelper(this.OperationContext))
                { 
                    PerformanceCounters.MethodReturnedSuccess(this.operationName, duration); 
                }
            } 
            if (TD2.OperationCompletedIsEnabled())
            {
                using (new OperationContextScopeHelper(this.OperationContext))
                { 
                    TD2.OperationCompleted(this.operationName,
                        TraceUtility.GetUtcBasedDurationForTrace(this.beginOperation)); 
                } 
            }
        } 

        void TrackMethodCompleted(object returnValue)
        {
            // WorkflowOperationInvoker always deals at the Message/Message level 
            Message faultMessage = returnValue as Message;
            if (faultMessage != null && faultMessage.IsFault) 
            { 
                TrackMethodFaulted();
            } 
            else
            {
                TrackMethodSucceeded();
            } 
        }
 
        bool ProcessRequest() 
        {
            this.TrackMethodCalled(); 
            this.ProcessInitializationTraces();

            if (this.notification == null)
            { 
                return OnResumeBookmark();
            } 
 
            string sessionId = this.OperationContext.SessionId;
            if (sessionId == null) 
            {
                return OnResumeBookmark();
            }
 
            // if there is a session, queue up this request in the per session pending request queue before notifying
            // the dispatcher to start the next invoke 
            IAsyncResult pendingAsyncResult = this.workflowInstance.BeginWaitForPendingOperations(sessionId, this.timeoutHelper.RemainingTime(), this.PrepareAsyncCompletion(handleEndWaitForPendingOperations), this); 
            bool completed;
 
            this.notification.NotifyInvokeReceived();
            if (pendingAsyncResult.CompletedSynchronously)
            {
                completed = HandleEndWaitForPendingOperations(pendingAsyncResult); 
            }
            else 
            { 
                completed = false;
            } 

            return completed;
        }
 
        void RemovePendingOperation()
        { 
            if (this.pendingAsyncResult != null) 
            {
                this.workflowInstance.RemovePendingOperation(this.OperationContext.SessionId, this.pendingAsyncResult); 
                this.pendingAsyncResult = null;
            }
        }
 
        static bool HandleEndWaitForPendingOperations(IAsyncResult result)
        { 
            WorkflowOperationContext thisPtr = (WorkflowOperationContext)result.AsyncState; 
            thisPtr.pendingAsyncResult = result;
 
            bool success = false;
            try
            {
                thisPtr.workflowInstance.EndWaitForPendingOperations(result); 
                bool retval = thisPtr.OnResumeBookmark();
                success = true; 
                return retval; 
            }
            finally 
            {
                if (!success)
                {
                    thisPtr.RemovePendingOperation(); 
                }
            } 
        } 

        bool OnResumeBookmark() 
        {
            bool success = false;
            try
            { 
                IAsyncResult nextResult = this.workflowInstance.BeginResumeProtocolBookmark(
                    this.bookmark, this.bookmarkScope, this, 
                    this.timeoutHelper.RemainingTime(), this.PrepareAsyncCompletion(handleEndResumeBookmark), this); 

                bool completed; 
                if (nextResult.CompletedSynchronously)
                {
                    completed = HandleEndResumeBookmark(nextResult);
                } 
                else
                { 
                    completed = false; 
                }
 
                success = true;
                return completed;
            }
            finally 
            {
                if (!success) 
                { 
                    this.RemovePendingOperation();
                } 
            }
        }

        static bool HandleEndResumeBookmark(IAsyncResult result) 
        {
            WorkflowOperationContext thisPtr = (WorkflowOperationContext)result.AsyncState; 
 
            bool completed = false;
            bool shouldAbandon = true; 
            try
            {
                BookmarkResumptionResult resumptionResult = thisPtr.workflowInstance.EndResumeProtocolBookmark(result);
                if (resumptionResult != BookmarkResumptionResult.Success) 
                {
                    // Raise UnkownMessageReceivedEvent when we fail to resume bookmark 
                    thisPtr.OperationContext.Host.RaiseUnknownMessageReceived(thisPtr.OperationContext.IncomingMessage); 

                    // Only delay-retry this operation once (and only if retries are supported). Future calls will ensure the bookmark is set. 
                    if (thisPtr.workflowInstance.BufferedReceiveManager != null)
                    {
                        bool bufferSuccess = thisPtr.workflowInstance.BufferedReceiveManager.BufferReceive(
                            thisPtr.OperationContext, thisPtr.receiveContext, thisPtr.bookmark.Name, BufferedReceiveState.WaitingOnBookmark, false); 
                        if (bufferSuccess)
                        { 
                            if (TD.BufferOutOfOrderMessageNoBookmarkIsEnabled()) 
                            {
                                TD.BufferOutOfOrderMessageNoBookmark(thisPtr.workflowInstance.Id.ToString(), thisPtr.bookmark.Name); 
                            }

                            shouldAbandon = false;
                        } 
                    }
 
                    // The throw exception is intentional whether or not BufferedReceiveManager is set. 
                    // This is to allow exception to bubble up the stack to WCF to cleanup various state (like Transaction).
                    // This is queue scenario and as far as the client is concerned, the client will not see any exception. 
                    throw FxTrace.Exception.AsError(new FaultException(OperationExecutionFault.CreateOperationNotAvailableFault(thisPtr.workflowInstance.Id, thisPtr.bookmark.Name)));
                }

                lock (thisPtr.thisLock) 
                {
                    if (thisPtr.CurrentState == State.ResultReceived) 
                    { 
                        thisPtr.CurrentState = State.Completed;
                        if (thisPtr.pendingException != null) 
                        {
                            throw FxTrace.Exception.AsError(thisPtr.pendingException);
                        }
                        completed = true; 
                    }
                    else 
                    { 
                        thisPtr.CurrentState = State.WaitForResult;
                        completed = false; 
                    }

                    // we are not really completed until the ReceiveContext finishes its work
                    if (completed) 
                    {
                        completed = thisPtr.ProcessReceiveContext(); 
                    } 

                    shouldAbandon = false; 
                }
            }
            finally
            { 
                if (shouldAbandon)
                { 
                    BufferedReceiveManager.AbandonReceiveContext(thisPtr.receiveContext); 
                }
                thisPtr.RemovePendingOperation(); 
            }

            return completed;
        } 

        bool ProcessReceiveContext() 
        { 
            if (this.receiveContext != null)
            { 
                if (handleEndProcessReceiveContext == null)
                {
                    handleEndProcessReceiveContext = new AsyncCompletion(HandleEndProcessReceiveContext);
                } 

                IAsyncResult nextResult = ReceiveContextAsyncResult.BeginProcessReceiveContext(this, this.receiveContext, PrepareAsyncCompletion(handleEndProcessReceiveContext), this); 
                return SyncContinue(nextResult); 
            }
 
            return true;
        }

        static bool HandleEndProcessReceiveContext(IAsyncResult result) 
        {
            ReceiveContextAsyncResult.EndProcessReceiveContext(result); 
            return true; 
        }
 
        static void Finally(AsyncResult result, Exception completionException)
        {
            WorkflowOperationContext thisPtr = (WorkflowOperationContext)result;
            thisPtr.EmitTransferFromInstanceId(); 

            if (completionException != null) 
            { 
                if (completionException is FaultException)
                { 
                    thisPtr.TrackMethodFaulted();
                }
                else
                { 
                    thisPtr.TrackMethodFailed();
                } 
            } 
            else
            { 
                thisPtr.TrackMethodCompleted(thisPtr.operationReturnValue);
            }
            thisPtr.ProcessFinalizationTraces();
            // will be a no-op if we were never added to the instance 
            thisPtr.workflowInstance.ReleaseContext(thisPtr);
            thisPtr.RemovePendingOperation(); 
        } 

        enum State 
        {
            BookmarkResumption,
            WaitForResult,
            ResultReceived, 
            Completed
        } 
 
        class OperationContextScopeHelper : IDisposable
        { 
            OperationContext currentOperationContext;

            public OperationContextScopeHelper(OperationContext operationContext)
            { 
                this.currentOperationContext = OperationContext.Current;
                OperationContext.Current = operationContext; 
            } 

            void IDisposable.Dispose() 
            {
                OperationContext.Current = this.currentOperationContext;
            }
        } 

        class ReceiveContextAsyncResult : AsyncResult 
        { 
            static AsyncCompletion handleEndComplete = new AsyncCompletion(HandleEndComplete);
 
            WorkflowOperationContext context;
            ReceiveContext receiveContext;

            ReceiveContextAsyncResult(WorkflowOperationContext context, ReceiveContext receiveContext, AsyncCallback callback, object state) 
                : base(callback, state)
            { 
                this.context = context; 
                this.receiveContext = receiveContext;
 
                if (ProcessReceiveContext())
                {
                    base.Complete(true);
                } 
            }
 
            public static IAsyncResult BeginProcessReceiveContext(WorkflowOperationContext context, ReceiveContext receiveContext, AsyncCallback callback, object state) 
            {
                return new ReceiveContextAsyncResult(context, receiveContext, callback, state); 
            }

            public static void EndProcessReceiveContext(IAsyncResult result)
            { 
                ReceiveContextAsyncResult.End(result);
            } 
 
            public static void End(IAsyncResult result)
            { 
                AsyncResult.End(result);
            }

            bool ProcessReceiveContext() 
            {
                IAsyncResult result; 
 
                using (PrepareTransactionalCall(this.context.CurrentTransaction))
                { 
                    if (this.context.CurrentTransaction != null)
                    {
                        // make sure we Abandon if the transaction ends up with an outcome of Aborted
                        this.context.CurrentTransaction.TransactionCompleted += new TransactionCompletedEventHandler(OnTransactionComplete); 
                    }
                    result = this.receiveContext.BeginComplete( 
                        this.context.timeoutHelper.RemainingTime(), PrepareAsyncCompletion(handleEndComplete), this); 
                }
 
                return SyncContinue(result);
            }

            // This happens out-of-band of ReceiveAsyncResult. 
            // When transaction was aborted, we best-effort abandon the context.
            void OnTransactionComplete(object sender, TransactionEventArgs e) 
            { 
                if (e.Transaction.TransactionInformation.Status != TransactionStatus.Committed)
                { 
                    BufferedReceiveManager.AbandonReceiveContext(this.context.receiveContext);
                }
            }
 
            static bool HandleEndComplete(IAsyncResult result)
            { 
                ReceiveContextAsyncResult thisPtr = (ReceiveContextAsyncResult)result.AsyncState; 
                thisPtr.receiveContext.EndComplete(result);
                return true; 
            }
        }
    }
} 

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