| File: System\ServiceModel\OperationContext.cs | Web Access |
| Project: src\src\System.ServiceModel.Primitives\src\System.ServiceModel.Primitives.csproj (System.ServiceModel.Primitives) |
// 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.Runtime; using System.Security.Claims; using System.Security.Principal; using System.ServiceModel.Channels; using System.ServiceModel.Dispatcher; using System.Threading; namespace System.ServiceModel { public sealed class OperationContext : IExtensibleObject<OperationContext> { static OperationContext() { DisableAsyncFlow = AppContext.TryGetSwitch("System.ServiceModel.OperationContext.DisableAsyncFlow", out var enabled) && enabled; if (!DisableAsyncFlow) { s_asyncContext = new AsyncLocal<OperationContext>(); } } [ThreadStatic] private static Holder s_currentContext; private static AsyncLocal<OperationContext> s_asyncContext; private Message _clientReply; private bool _closeClientReply; private ExtensionCollection<OperationContext> _extensions; private Message _request; private bool _isServiceReentrant = false; internal IPrincipal threadPrincipal; private MessageProperties _outgoingMessageProperties; private MessageHeaders _outgoingMessageHeaders; private EndpointDispatcher _endpointDispatcher; public event EventHandler OperationCompleted; public OperationContext(IContextChannel channel) { if (channel == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException(nameof(channel))); } ServiceChannel serviceChannel = channel as ServiceChannel; //Could be a TransparentProxy if (serviceChannel == null) { serviceChannel = ServiceChannelFactory.GetServiceChannel(channel); } if (serviceChannel != null) { OutgoingMessageVersion = serviceChannel.MessageVersion; InternalServiceChannel = serviceChannel; } else { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SRP.SFxInvalidChannelToOperationContext)); } } internal OperationContext() : this(MessageVersion.Soap12WSAddressing10) { } internal OperationContext(MessageVersion outgoingMessageVersion) { OutgoingMessageVersion = outgoingMessageVersion ?? throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException(nameof(outgoingMessageVersion))); } internal OperationContext(RequestContext requestContext, Message request, ServiceChannel channel) { InternalServiceChannel = channel; RequestContext = requestContext; _request = request; OutgoingMessageVersion = channel.MessageVersion; } public IContextChannel Channel { get { return GetCallbackChannel<IContextChannel>(); } } public static OperationContext Current { get { if (DisableAsyncFlow) { return CurrentHolder.Context; } else { return s_asyncContext.Value; } } set { if (DisableAsyncFlow) { CurrentHolder.Context = value; } else { s_asyncContext.Value = value; } } } internal static Holder CurrentHolder { get { Holder holder; holder = s_currentContext; if (holder == null) { holder = new Holder(); s_currentContext = holder; } return holder; } } internal static bool DisableAsyncFlow { get; } public EndpointDispatcher EndpointDispatcher { get { return _endpointDispatcher; } set { _endpointDispatcher = value; } } public bool IsUserContext { get { return (_request == null); } } public IExtensionCollection<OperationContext> Extensions { get { if (_extensions == null) { _extensions = new ExtensionCollection<OperationContext>(this); } return _extensions; } } internal bool IsServiceReentrant { get { return _isServiceReentrant; } set { _isServiceReentrant = value; } } internal Message IncomingMessage { get { return _clientReply ?? _request; } } internal ServiceChannel InternalServiceChannel { get; set; } internal bool HasOutgoingMessageHeaders { get { return (_outgoingMessageHeaders != null); } } public MessageHeaders OutgoingMessageHeaders { get { if (_outgoingMessageHeaders == null) { _outgoingMessageHeaders = new MessageHeaders(OutgoingMessageVersion); } return _outgoingMessageHeaders; } } internal bool HasOutgoingMessageProperties { get { return (_outgoingMessageProperties != null); } } public MessageProperties OutgoingMessageProperties { get { if (_outgoingMessageProperties == null) { _outgoingMessageProperties = new MessageProperties(); } return _outgoingMessageProperties; } } internal MessageVersion OutgoingMessageVersion { get; } public MessageHeaders IncomingMessageHeaders { get { Message message = _clientReply ?? _request; if (message != null) { return message.Headers; } else { return null; } } } public MessageProperties IncomingMessageProperties { get { Message message = _clientReply ?? _request; if (message != null) { return message.Properties; } else { return null; } } } public MessageVersion IncomingMessageVersion { get { Message message = _clientReply ?? _request; if (message != null) { return message.Version; } else { return null; } } } public InstanceContext InstanceContext { get; private set; } public RequestContext RequestContext { get; set; } public string SessionId { get { if (InternalServiceChannel != null) { IChannel inner = InternalServiceChannel.InnerChannel; if (inner != null) { ISessionChannel<IDuplexSession> duplex = inner as ISessionChannel<IDuplexSession>; if ((duplex != null) && (duplex.Session != null)) { return duplex.Session.Id; } ISessionChannel<IInputSession> input = inner as ISessionChannel<IInputSession>; if ((input != null) && (input.Session != null)) { return input.Session.Id; } ISessionChannel<IOutputSession> output = inner as ISessionChannel<IOutputSession>; if ((output != null) && (output.Session != null)) { return output.Session.Id; } } } return null; } } internal IPrincipal ThreadPrincipal { get { return threadPrincipal; } set { threadPrincipal = value; } } public ClaimsPrincipal ClaimsPrincipal { get; internal set; } internal void ClearClientReplyNoThrow() { _clientReply = null; } internal void FireOperationCompleted() { try { EventHandler handler = OperationCompleted; if (handler != null) { handler(this, EventArgs.Empty); } } catch (Exception e) { if (Fx.IsFatal(e)) { throw; } throw DiagnosticUtility.ExceptionUtility.ThrowHelperCallback(e); } } public T GetCallbackChannel<T>() { if (InternalServiceChannel == null || IsUserContext) { return default(T); } // yes, we might throw InvalidCastException here. Is it really // better to check and throw something else instead? return (T)InternalServiceChannel.Proxy; } internal void ReInit(RequestContext requestContext, Message request, ServiceChannel channel) { RequestContext = requestContext; _request = request; InternalServiceChannel = channel; } internal void Recycle() { RequestContext = null; _request = null; _extensions = null; InstanceContext = null; threadPrincipal = null; SetClientReply(null, false); } internal void SetClientReply(Message message, bool closeMessage) { Message oldClientReply = null; if (!object.Equals(message, _clientReply)) { if (_closeClientReply && (_clientReply != null)) { oldClientReply = _clientReply; } _clientReply = message; } _closeClientReply = closeMessage; if (oldClientReply != null) { oldClientReply.Close(); } } internal void SetInstanceContext(InstanceContext instanceContext) { InstanceContext = instanceContext; } internal class Holder { public OperationContext Context { get; set; } } } }