| File: FrameworkFork\System.ServiceModel\System\ServiceModel\Dispatcher\MessageRpc.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.Collections.ObjectModel; using System.Diagnostics; using System.Runtime; using System.Runtime.CompilerServices; using System.Runtime.Diagnostics; using System.Security; using System.ServiceModel.Channels; using System.ServiceModel.Diagnostics; using Microsoft.Xml; namespace System.ServiceModel.Dispatcher { internal delegate void MessageRpcProcessor(ref MessageRpc rpc); internal struct MessageRpc { internal readonly ServiceChannel Channel; internal readonly ChannelHandler channelHandler; internal readonly object[] Correlation; internal readonly OperationContext OperationContext; internal ServiceModelActivity Activity; internal Guid ResponseActivityId; internal IAsyncResult AsyncResult; internal bool CanSendReply; internal bool SuccessfullySendReply; internal object[] InputParameters; internal object[] OutputParameters; internal object ReturnParameter; internal bool ParametersDisposed; internal bool DidDeserializeRequestBody; internal Exception Error; internal MessageRpcProcessor ErrorProcessor; internal ErrorHandlerFaultInfo FaultInfo; internal bool HasSecurityContext; internal object Instance; internal bool MessageRpcOwnsInstanceContextThrottle; internal MessageRpcProcessor NextProcessor; internal Collection<MessageHeaderInfo> NotUnderstoodHeaders; internal DispatchOperationRuntime Operation; internal Message Request; internal RequestContext RequestContext; internal bool RequestContextThrewOnReply; internal UniqueId RequestID; internal Message Reply; internal TimeoutHelper ReplyTimeoutHelper; internal RequestReplyCorrelator.ReplyToInfo ReplyToInfo; internal MessageVersion RequestVersion; internal ServiceSecurityContext SecurityContext; internal InstanceContext InstanceContext; internal bool SuccessfullyBoundInstance; internal bool SuccessfullyIncrementedActivity; internal bool SuccessfullyLockedInstance; internal MessageRpcInvokeNotification InvokeNotification; internal EventTraceActivity EventTraceActivity; private bool _paused; private bool _switchedThreads; private bool _isInstanceContextSingleton; private SignalGate<IAsyncResult> _invokeContinueGate; internal MessageRpc(RequestContext requestContext, Message request, DispatchOperationRuntime operation, ServiceChannel channel, ChannelHandler channelHandler, bool cleanThread, OperationContext operationContext, InstanceContext instanceContext, EventTraceActivity eventTraceActivity) { Fx.Assert((operationContext != null), "System.ServiceModel.Dispatcher.MessageRpc.MessageRpc(), operationContext == null"); Fx.Assert(channelHandler != null, "System.ServiceModel.Dispatcher.MessageRpc.MessageRpc(), channelHandler == null"); this.Activity = null; this.EventTraceActivity = eventTraceActivity; this.AsyncResult = null; this.CanSendReply = true; this.Channel = channel; this.channelHandler = channelHandler; this.Correlation = EmptyArray<object>.Allocate(operation.Parent.CorrelationCount); this.DidDeserializeRequestBody = false; this.Error = null; this.ErrorProcessor = null; this.FaultInfo = new ErrorHandlerFaultInfo(request.Version.Addressing.DefaultFaultAction); this.HasSecurityContext = false; this.Instance = null; this.MessageRpcOwnsInstanceContextThrottle = false; this.NextProcessor = null; this.NotUnderstoodHeaders = null; this.Operation = operation; this.OperationContext = operationContext; _paused = false; this.ParametersDisposed = false; this.Request = request; this.RequestContext = requestContext; this.RequestContextThrewOnReply = false; this.SuccessfullySendReply = false; this.RequestVersion = request.Version; this.Reply = null; this.ReplyTimeoutHelper = new TimeoutHelper(); this.SecurityContext = null; this.InstanceContext = instanceContext; this.SuccessfullyBoundInstance = false; this.SuccessfullyIncrementedActivity = false; this.SuccessfullyLockedInstance = false; _switchedThreads = !cleanThread; this.InputParameters = null; this.OutputParameters = null; this.ReturnParameter = null; _isInstanceContextSingleton = false; _invokeContinueGate = null; if (!operation.IsOneWay && !operation.Parent.ManualAddressing) { this.RequestID = request.Headers.MessageId; this.ReplyToInfo = new RequestReplyCorrelator.ReplyToInfo(request); } else { this.RequestID = null; this.ReplyToInfo = new RequestReplyCorrelator.ReplyToInfo(); } if (DiagnosticUtility.ShouldUseActivity) { this.Activity = TraceUtility.ExtractActivity(this.Request); } if (DiagnosticUtility.ShouldUseActivity || TraceUtility.ShouldPropagateActivity) { this.ResponseActivityId = ActivityIdHeader.ExtractActivityId(this.Request); } else { this.ResponseActivityId = Guid.Empty; } this.InvokeNotification = new MessageRpcInvokeNotification(this.Activity, this.channelHandler); if (this.EventTraceActivity == null && FxTrace.Trace.IsEnd2EndActivityTracingEnabled) { if (this.Request != null) { this.EventTraceActivity = EventTraceActivityHelper.TryExtractActivity(this.Request, true); } } } internal bool IsPaused { get { return _paused; } } internal bool SwitchedThreads { get { return _switchedThreads; } } internal void Abort() { this.AbortRequestContext(); this.AbortChannel(); this.AbortInstanceContext(); } private void AbortRequestContext(RequestContext requestContext) { try { requestContext.Abort(); } catch (Exception e) { if (Fx.IsFatal(e)) { throw; } this.channelHandler.HandleError(e); } } internal void AbortRequestContext() { if (this.OperationContext.RequestContext != null) { this.AbortRequestContext(this.OperationContext.RequestContext); } if ((this.RequestContext != null) && (this.RequestContext != this.OperationContext.RequestContext)) { this.AbortRequestContext(this.RequestContext); } TraceCallDurationInDispatcherIfNecessary(false); } private void TraceCallDurationInDispatcherIfNecessary(bool requestContextWasClosedSuccessfully) { } internal void CloseRequestContext() { if (this.OperationContext.RequestContext != null) { this.DisposeRequestContext(this.OperationContext.RequestContext); } if ((this.RequestContext != null) && (this.RequestContext != this.OperationContext.RequestContext)) { this.DisposeRequestContext(this.RequestContext); } TraceCallDurationInDispatcherIfNecessary(true); } private void DisposeRequestContext(RequestContext context) { try { context.Close(); } catch (Exception e) { if (Fx.IsFatal(e)) { throw; } this.AbortRequestContext(context); this.channelHandler.HandleError(e); } } internal void AbortChannel() { if ((this.Channel != null) && this.Channel.HasSession) { try { this.Channel.Abort(); } catch (Exception e) { if (Fx.IsFatal(e)) { throw; } this.channelHandler.HandleError(e); } } } internal void CloseChannel() { if ((this.Channel != null) && this.Channel.HasSession) { try { this.Channel.Close(ChannelHandler.CloseAfterFaultTimeout); } catch (Exception e) { if (Fx.IsFatal(e)) { throw; } this.channelHandler.HandleError(e); } } } internal void AbortInstanceContext() { if (this.InstanceContext != null && !_isInstanceContextSingleton) { try { this.InstanceContext.Abort(); } catch (Exception e) { if (Fx.IsFatal(e)) { throw; } this.channelHandler.HandleError(e); } } } internal void EnsureReceive() { using (ServiceModelActivity.BoundOperation(this.Activity)) { ChannelHandler.Register(this.channelHandler); } } private bool ProcessError(Exception e) { MessageRpcProcessor handler = this.ErrorProcessor; try { if (TraceUtility.MessageFlowTracingOnly) { TraceUtility.SetActivityId(this.Request.Properties); if (Guid.Empty == DiagnosticTraceBase.ActivityId) { Guid receivedActivityId = TraceUtility.ExtractActivityId(this.Request); if (Guid.Empty != receivedActivityId) { DiagnosticTraceBase.ActivityId = receivedActivityId; } } } this.Error = e; if (this.ErrorProcessor != null) { this.ErrorProcessor(ref this); } return (this.Error == null); } #pragma warning disable 56500 // covered by FxCOP catch (Exception e2) { if (Fx.IsFatal(e2)) { throw; } return ((handler != this.ErrorProcessor) && this.ProcessError(e2)); } } internal void DisposeParameters(bool excludeInput) { if (this.Operation.DisposeParameters) { this.DisposeParametersCore(excludeInput); } } internal void DisposeParametersCore(bool excludeInput) { if (!this.ParametersDisposed) { if (!excludeInput) { this.DisposeParameterList(this.InputParameters); } this.DisposeParameterList(this.OutputParameters); IDisposable disposableParameter = this.ReturnParameter as IDisposable; if (disposableParameter != null) { try { disposableParameter.Dispose(); } catch (Exception e) { if (Fx.IsFatal(e)) { throw; } this.channelHandler.HandleError(e); } } this.ParametersDisposed = true; } } private void DisposeParameterList(object[] parameters) { IDisposable disposableParameter = null; if (parameters != null) { foreach (Object obj in parameters) { disposableParameter = obj as IDisposable; if (disposableParameter != null) { try { disposableParameter.Dispose(); } catch (Exception e) { if (Fx.IsFatal(e)) { throw; } this.channelHandler.HandleError(e); } } } } } // See notes on UnPause and Resume (mutually exclusive) // Pausing will Increment the BusyCount for the hosting environment internal IResumeMessageRpc Pause() { Wrapper wrapper = new Wrapper(ref this); _paused = true; return wrapper; } [Fx.Tag.SecurityNote(Critical = "Calls SecurityCritical method ApplyHostingIntegrationContext.", Safe = "Does call properly and calls Dispose, doesn't leak control of the IDisposable out of the function.")] [SecuritySafeCritical] internal bool Process(bool isOperationContextSet) { using (ServiceModelActivity.BoundOperation(this.Activity)) { bool completed = true; if (this.NextProcessor != null) { MessageRpcProcessor processor = this.NextProcessor; this.NextProcessor = null; OperationContext originalContext; OperationContext.Holder contextHolder; if (!isOperationContextSet) { contextHolder = OperationContext.CurrentHolder; originalContext = contextHolder.Context; } else { contextHolder = null; originalContext = null; } IncrementBusyCount(); try { if (!isOperationContextSet) { contextHolder.Context = this.OperationContext; } processor(ref this); if (!_paused) { this.OperationContext.SetClientReply(null, false); } } #pragma warning disable 56500 // covered by FxCOP catch (Exception e) { if (Fx.IsFatal(e)) { throw; } if (!this.ProcessError(e) && this.FaultInfo.Fault == null) { this.Abort(); } } finally { try { DecrementBusyCount(); if (!isOperationContextSet) { contextHolder.Context = originalContext; } completed = !_paused; if (completed) { this.channelHandler.DispatchDone(); this.OperationContext.ClearClientReplyNoThrow(); } } #pragma warning disable 56500 // covered by FxCOP catch (Exception e) { if (Fx.IsFatal(e)) { throw; } throw DiagnosticUtility.ExceptionUtility.ThrowHelperFatal(e.Message, e); } } } return completed; } } // UnPause is called on the original MessageRpc to continue work on the current thread, and the copy is ignored. // Since the copy is ignored, Decrement the BusyCount internal void UnPause() { _paused = false; DecrementBusyCount(); } internal bool UnlockInvokeContinueGate(out IAsyncResult result) { return _invokeContinueGate.Unlock(out result); } internal void PrepareInvokeContinueGate() { _invokeContinueGate = new SignalGate<IAsyncResult>(); } private void IncrementBusyCount() { } private void DecrementBusyCount() { } private class CallbackState { public ChannelHandler ChannelHandler { get; set; } } internal class Wrapper : IResumeMessageRpc { private MessageRpc _rpc; private bool _alreadyResumed; internal Wrapper(ref MessageRpc rpc) { _rpc = rpc; if (rpc.NextProcessor == null) { Fx.Assert("MessageRpc.Wrapper.Wrapper: (rpc.NextProcessor != null)"); } _rpc.IncrementBusyCount(); } public InstanceContext GetMessageInstanceContext() { return _rpc.InstanceContext; } // Resume is called on the copy on some completing thread, whereupon work continues on that thread. // BusyCount is Decremented as the copy is now complete public void Resume(out bool alreadyResumedNoLock) { try { alreadyResumedNoLock = _alreadyResumed; _alreadyResumed = true; _rpc._switchedThreads = true; if (_rpc.Process(false) && !_rpc.InvokeNotification.DidInvokerEnsurePump) { _rpc.EnsureReceive(); } } finally { _rpc.DecrementBusyCount(); } } public void Resume(IAsyncResult result) { _rpc.AsyncResult = result; this.Resume(); } public void Resume(object instance) { _rpc.Instance = instance; this.Resume(); } public void Resume() { using (ServiceModelActivity.BoundOperation(_rpc.Activity, true)) { bool alreadyResumedNoLock; this.Resume(out alreadyResumedNoLock); if (alreadyResumedNoLock) { string text = string.Format(SRServiceModel.SFxMultipleCallbackFromAsyncOperation, String.Empty); Exception error = new InvalidOperationException(text); throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(error); } } } public void SignalConditionalResume(IAsyncResult result) { if (_rpc._invokeContinueGate.Signal(result)) { _rpc.AsyncResult = result; Resume(); } } } } internal class MessageRpcInvokeNotification : IInvokeReceivedNotification { private ServiceModelActivity _activity; private ChannelHandler _handler; public MessageRpcInvokeNotification(ServiceModelActivity activity, ChannelHandler handler) { _activity = activity; _handler = handler; } public bool DidInvokerEnsurePump { get; set; } public void NotifyInvokeReceived() { using (ServiceModelActivity.BoundOperation(_activity)) { ChannelHandler.Register(_handler); } this.DidInvokerEnsurePump = true; } public void NotifyInvokeReceived(RequestContext request) { using (ServiceModelActivity.BoundOperation(_activity)) { ChannelHandler.Register(_handler, request); } this.DidInvokerEnsurePump = true; } } }