| File: FrameworkFork\System.ServiceModel\System\ServiceModel\Dispatcher\DispatchOperationRuntime.cs | Web Access |
| Project: src\src\dotnet-svcutil\lib\src\dotnet-svcutil-lib.csproj (dotnet-svcutil-lib) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System; using System.Collections.Generic; using System.Linq; using System.Runtime; using System.Security.Principal; using System.ServiceModel.Channels; using System.ServiceModel.Diagnostics; using System.Text; using System.Threading.Tasks; namespace System.ServiceModel.Dispatcher { internal class DispatchOperationRuntime { private static AsyncCallback s_invokeCallback = Fx.ThunkCallback(DispatchOperationRuntime.InvokeCallback); private readonly string _action; private IDispatchFaultFormatter _faultFormatter; private readonly IDispatchMessageFormatter _formatter; private IParameterInspector[] _inspectors; private readonly IOperationInvoker _invoker; private readonly bool _isSessionOpenNotificationEnabled; private readonly string _name; private readonly ImmutableDispatchRuntime _parent; private readonly string _replyAction; private readonly bool _deserializeRequest; private readonly bool _serializeReply; private readonly bool _isOneWay; private readonly bool _disposeParameters; internal DispatchOperationRuntime(DispatchOperation operation, ImmutableDispatchRuntime parent) { if (operation == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("operation"); } if (parent == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("parent"); } if (operation.Invoker == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SRServiceModel.RuntimeRequiresInvoker0)); } _disposeParameters = ((operation.AutoDisposeParameters) && (!operation.HasNoDisposableParameters)); _parent = parent; _inspectors = EmptyArray<IParameterInspector>.ToArray(operation.ParameterInspectors); _faultFormatter = operation.FaultFormatter; _deserializeRequest = operation.DeserializeRequest; _serializeReply = operation.SerializeReply; _formatter = operation.Formatter; _invoker = operation.Invoker; _isSessionOpenNotificationEnabled = operation.IsSessionOpenNotificationEnabled; _action = operation.Action; _name = operation.Name; _replyAction = operation.ReplyAction; _isOneWay = operation.IsOneWay; if (_formatter == null && (_deserializeRequest || _serializeReply)) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(string.Format(SRServiceModel.DispatchRuntimeRequiresFormatter0, _name))); } } internal string Action { get { return _action; } } internal bool DisposeParameters { get { return _disposeParameters; } } internal IDispatchFaultFormatter FaultFormatter { get { return _faultFormatter; } } internal IDispatchMessageFormatter Formatter { get { return _formatter; } } internal IOperationInvoker Invoker { get { return _invoker; } } internal bool IsOneWay { get { return _isOneWay; } } internal string Name { get { return _name; } } internal IParameterInspector[] ParameterInspectors { get { return _inspectors; } } internal ImmutableDispatchRuntime Parent { get { return _parent; } } internal string ReplyAction { get { return _replyAction; } } private void DeserializeInputs(ref MessageRpc rpc) { bool success = false; try { rpc.InputParameters = this.Invoker.AllocateInputs(); // If the field is true, then this operation is to be invoked at the time the service // channel is opened. The incoming message is created at ChannelHandler level with no // content, so we don't need to deserialize the message. if (!_isSessionOpenNotificationEnabled) { if (_deserializeRequest) { if (WcfEventSource.Instance.DispatchFormatterDeserializeRequestStartIsEnabled()) { WcfEventSource.Instance.DispatchFormatterDeserializeRequestStart(rpc.EventTraceActivity); } this.Formatter.DeserializeRequest(rpc.Request, rpc.InputParameters); if (WcfEventSource.Instance.DispatchFormatterDeserializeRequestStopIsEnabled()) { WcfEventSource.Instance.DispatchFormatterDeserializeRequestStop(rpc.EventTraceActivity); } } else { rpc.InputParameters[0] = rpc.Request; } } success = true; } finally { rpc.DidDeserializeRequestBody = (rpc.Request.State != MessageState.Created); if (!success && MessageLogger.LoggingEnabled) { MessageLogger.LogMessage(ref rpc.Request, MessageLoggingSource.Malformed); } } } private void InspectInputs(ref MessageRpc rpc) { if (this.ParameterInspectors.Length > 0) { InspectInputsCore(ref rpc); } } private void InspectInputsCore(ref MessageRpc rpc) { for (int i = 0; i < this.ParameterInspectors.Length; i++) { IParameterInspector inspector = this.ParameterInspectors[i]; rpc.Correlation[i] = inspector.BeforeCall(this.Name, rpc.InputParameters); if (WcfEventSource.Instance.ParameterInspectorBeforeCallInvokedIsEnabled()) { WcfEventSource.Instance.ParameterInspectorBeforeCallInvoked(rpc.EventTraceActivity, this.ParameterInspectors[i].GetType().FullName); } } } private void InspectOutputs(ref MessageRpc rpc) { if (this.ParameterInspectors.Length > 0) { InspectOutputsCore(ref rpc); } } private void InspectOutputsCore(ref MessageRpc rpc) { for (int i = this.ParameterInspectors.Length - 1; i >= 0; i--) { IParameterInspector inspector = this.ParameterInspectors[i]; inspector.AfterCall(this.Name, rpc.OutputParameters, rpc.ReturnParameter, rpc.Correlation[i]); if (WcfEventSource.Instance.ParameterInspectorAfterCallInvokedIsEnabled()) { WcfEventSource.Instance.ParameterInspectorAfterCallInvoked(rpc.EventTraceActivity, this.ParameterInspectors[i].GetType().FullName); } } } internal void InvokeBegin(ref MessageRpc rpc) { if (rpc.Error == null) { object target = rpc.Instance; this.DeserializeInputs(ref rpc); this.InspectInputs(ref rpc); ValidateMustUnderstand(ref rpc); IAsyncResult result; bool isBeginSuccessful = false; IResumeMessageRpc resumeRpc = rpc.Pause(); try { result = Invoker.InvokeBegin(target, rpc.InputParameters, s_invokeCallback, resumeRpc); isBeginSuccessful = true; } finally { if (!isBeginSuccessful) { rpc.UnPause(); } } if (result == null) { throw TraceUtility.ThrowHelperError(new ArgumentNullException("IOperationInvoker.BeginDispatch"), rpc.Request); } if (result.CompletedSynchronously) { // if the async call completed synchronously, then the responsibility to call // ProcessMessage{6,7,Cleanup} still remains on this thread rpc.UnPause(); rpc.AsyncResult = result; } } } private static void InvokeCallback(IAsyncResult result) { if (result.CompletedSynchronously) { return; } IResumeMessageRpc resume = result.AsyncState as IResumeMessageRpc; if (resume == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(SRServiceModel.SFxInvalidAsyncResultState0); } resume.SignalConditionalResume(result); } internal void InvokeEnd(ref MessageRpc rpc) { if ((rpc.Error == null)) { rpc.ReturnParameter = this.Invoker.InvokeEnd(rpc.Instance, out rpc.OutputParameters, rpc.AsyncResult); this.InspectOutputs(ref rpc); this.SerializeOutputs(ref rpc); } } private void SerializeOutputs(ref MessageRpc rpc) { if (!this.IsOneWay && _parent.EnableFaults) { Message reply; if (_serializeReply) { if (WcfEventSource.Instance.DispatchFormatterSerializeReplyStartIsEnabled()) { WcfEventSource.Instance.DispatchFormatterSerializeReplyStart(rpc.EventTraceActivity); } reply = this.Formatter.SerializeReply(rpc.RequestVersion, rpc.OutputParameters, rpc.ReturnParameter); if (WcfEventSource.Instance.DispatchFormatterSerializeReplyStopIsEnabled()) { WcfEventSource.Instance.DispatchFormatterSerializeReplyStop(rpc.EventTraceActivity); } if (reply == null) { string message = string.Format(SRServiceModel.SFxNullReplyFromFormatter2, this.Formatter.GetType().ToString(), (_name ?? "")); ErrorBehavior.ThrowAndCatch(new InvalidOperationException(message)); } } else { if ((rpc.ReturnParameter == null) && (rpc.OperationContext.RequestContext != null)) { string message = string.Format(SRServiceModel.SFxDispatchRuntimeMessageCannotBeNull, _name); ErrorBehavior.ThrowAndCatch(new InvalidOperationException(message)); } reply = (Message)rpc.ReturnParameter; if ((reply != null) && (!ProxyOperationRuntime.IsValidAction(reply, this.ReplyAction))) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(string.Format(SRServiceModel.SFxInvalidReplyAction, this.Name, reply.Headers.Action ?? "{NULL}", this.ReplyAction))); } } if (DiagnosticUtility.ShouldUseActivity && rpc.Activity != null && reply != null) { TraceUtility.SetActivity(reply, rpc.Activity); if (TraceUtility.ShouldPropagateActivity) { TraceUtility.AddActivityHeader(reply); } } else if (TraceUtility.ShouldPropagateActivity && reply != null && rpc.ResponseActivityId != Guid.Empty) { ActivityIdHeader header = new ActivityIdHeader(rpc.ResponseActivityId); header.AddTo(reply); } //rely on the property set during the message receive to correlate the trace if (TraceUtility.MessageFlowTracingOnly) { //Guard against MEX scenarios where the message is closed by now if (null != rpc.OperationContext.IncomingMessage && MessageState.Closed != rpc.OperationContext.IncomingMessage.State) { FxTrace.Trace.SetAndTraceTransfer(TraceUtility.GetReceivedActivityId(rpc.OperationContext), true); } else { if (rpc.ResponseActivityId != Guid.Empty) { FxTrace.Trace.SetAndTraceTransfer(rpc.ResponseActivityId, true); } } } if (MessageLogger.LoggingEnabled && null != reply) { MessageLogger.LogMessage(ref reply, MessageLoggingSource.ServiceLevelSendReply | MessageLoggingSource.LastChance); } rpc.Reply = reply; } } private void ValidateMustUnderstand(ref MessageRpc rpc) { if (_parent.ValidateMustUnderstand) { rpc.NotUnderstoodHeaders = rpc.Request.Headers.GetHeadersNotUnderstood(); if (rpc.NotUnderstoodHeaders != null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new MustUnderstandSoapException(rpc.NotUnderstoodHeaders, rpc.Request.Version.Envelope)); } } } } }