//------------------------------------------------------------ // 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 contextProperties; ReadOnlyCollection inputs; [NonSerialized] OperationContext operationContext; SerializableAuthorizationContext serializedAuthorizationContext; public WorkflowRequestContext(WorkflowOperationAsyncResult asyncResult, object[] inputs, IDictionary contextProperties) { if (asyncResult == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("asyncResult"); } if (inputs == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("inputs"); } this.asyncResult = asyncResult; this.inputs = new ReadOnlyCollection(inputs); this.contextProperties = contextProperties ?? SerializableReadOnlyDictionary.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 ContextProperties { get { return this.contextProperties; } } public ReadOnlyCollection 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 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 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; } } } }