File: System\ServiceModel\Dispatcher\WorkflowRequestContext.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.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Diagnostics.CodeAnalysis;
    using System.IdentityModel.Policy;
    using System.Runtime;
    using System.Runtime.Diagnostics;
    using System.Runtime.Serialization;
    using System.ServiceModel.Diagnostics;
    using System.ServiceModel.Security;
    using System.Diagnostics;
 
    [Serializable]
    class WorkflowRequestContext
    {
        [NonSerialized]
        WorkflowOperationAsyncResult asyncResult;
 
        [NonSerialized]
        AuthorizationContext authorizationContext;
 
        IDictionary<string, string> contextProperties;
        ReadOnlyCollection<object> inputs;
 
        [NonSerialized]
        OperationContext operationContext;
 
        SerializableAuthorizationContext serializedAuthorizationContext;
 
        public WorkflowRequestContext(WorkflowOperationAsyncResult asyncResult, object[] inputs, IDictionary<string, string> contextProperties)
        {
            if (asyncResult == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("asyncResult");
            }
 
            if (inputs == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("inputs");
            }
 
            this.asyncResult = asyncResult;
            this.inputs = new ReadOnlyCollection<object>(inputs);
            this.contextProperties = contextProperties ?? SerializableReadOnlyDictionary<string, string>.Empty;
            this.operationContext = OperationContext.Current;
        }
 
        public AuthorizationContext AuthorizationContext
        {
            get
            {
                if (this.authorizationContext == null)
                {
                    if (this.serializedAuthorizationContext != null)
                    {
                        this.authorizationContext = serializedAuthorizationContext.Retrieve();
                    }
                }
                return authorizationContext;
            }
        }
 
        public IDictionary<string, string> ContextProperties
        {
            get
            {
                return this.contextProperties;
            }
        }
 
        public ReadOnlyCollection<object> Inputs
        {
            get
            {
                return this.inputs;
            }
        }
 
        public void PopulateAuthorizationState()
        {
            if (OperationContext.Current == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR2.GetString(SR2.NoOperationContext)));
            }
 
            if (OperationContext.Current.ServiceSecurityContext != null)
            {
                this.authorizationContext = OperationContext.Current.ServiceSecurityContext.AuthorizationContext;
            }
        }
 
        public void SendFault(Exception exception, IDictionary<string, string> outgoingContextProperties)
        {
            if (exception == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("exception");
            }
 
            if (!(exception is FaultException)) //Wrap the exception if it is not FaultException.
            {
                exception = WorkflowOperationErrorHandler.CreateUnhandledException(exception);
            }
 
            WorkflowOperationAsyncResult asyncResult = this.GetAsyncResult();
            asyncResult.SendFault(exception, outgoingContextProperties);
            this.SetOperationCompleted();
 
            if (DiagnosticUtility.ShouldTraceInformation)
            {
                string traceText = SR.GetString(SR.TraceCodeWorkflowRequestContextFaultSent, asyncResult.InstanceId);
                TraceUtility.TraceEvent(TraceEventType.Information,
                    TraceCode.WorkflowRequestContextFaultSent, traceText, 
                    new StringTraceRecord("Details", traceText),
                    this,
                    exception);
            }
        }
 
        public void SendReply(object returnValue, object[] outputs, IDictionary<string, string> outgoingContextProperties)
        {
            if (outputs == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("outputs");
            }
 
            WorkflowOperationAsyncResult asyncResult = this.GetAsyncResult();
            asyncResult.SendResponse(returnValue, outputs, outgoingContextProperties);
            this.SetOperationCompleted();
 
            if (DiagnosticUtility.ShouldTraceVerbose)
            {
                string traceText = SR.GetString(SR.TraceCodeWorkflowRequestContextReplySent, asyncResult.InstanceId);
                TraceUtility.TraceEvent(TraceEventType.Verbose,
                    TraceCode.WorkflowRequestContextReplySent, traceText,
                    new StringTraceRecord("Details", traceText),
                    this, null);
            }
        }
 
        public void SetOperationCompleted()
        {
            OperationContext.Current = this.operationContext;
 
            try
            {
                this.GetAsyncResult().MarkOneWayOperationCompleted();
            }
            catch (Exception e)
            {
                if (Fx.IsFatal(e))
                {
                    throw;
                }
                //For Two-ways it is no-op; For One-ways make it fire & forget.
            }
        }
 
        internal WorkflowOperationAsyncResult GetAsyncResult()
        {
            if (this.asyncResult == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR2.GetString(SR2.UnloadedBeforeResponse)));
            }
            return asyncResult;
        }
 
        //To be called by dispatcher before EnqueueItemOnIdle.
        internal void SetOperationBegin()
        {
            OperationContext current = OperationContext.Current;
            OperationContext.Current = this.operationContext;
            this.operationContext = current;
        }
 
        [OnSerializing]
        [SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters")]
        void OnSerializing(StreamingContext context)
        {
            if (this.serializedAuthorizationContext == null)
            {
                if (this.authorizationContext != null)
                {
                    this.serializedAuthorizationContext = SerializableAuthorizationContext.From(this.authorizationContext);
                }
            }
            if (this.asyncResult != null)
            {
                // Serialization time is the only reasonable hook point to determine that the workflow 
                // is not going to be able to send back a response (because asyncResult does not serialize). 
                // Setting this flag on the async result enables the logic in WorkflowInstanceContextProvider.OnWorkflowActivationCompleted
                // to complete the operation from service model's perspective. 
                this.asyncResult.HasWorkflowRequestContextBeenSerialized = true;
            }
        }
    }
}