| File: FrameworkFork\System.ServiceModel\System\ServiceModel\Dispatcher\DispatchRuntime.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.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.IdentityModel.Policy; using System.Runtime; using System.ServiceModel.Channels; using System.ServiceModel.Description; using System.ServiceModel.Diagnostics; using System.Threading; using System.Runtime.Diagnostics; using System.Diagnostics.Contracts; using System.Threading.Tasks; namespace System.ServiceModel.Dispatcher { public sealed class DispatchRuntime { private ConcurrencyMode _concurrencyMode; private bool _ensureOrderedDispatch; private bool _automaticInputSessionShutdown; private ChannelDispatcher _channelDispatcher; private EndpointDispatcher _endpointDispatcher = null; private IInstanceProvider _instanceProvider; private IInstanceContextProvider _instanceContextProvider; private OperationCollection _operations; private ClientRuntime _proxyRuntime; private ImmutableDispatchRuntime _runtime; private SynchronizationContext _synchronizationContext; private Type _type; private DispatchOperation _unhandled; private SharedRuntimeState _shared; internal DispatchRuntime(ClientRuntime proxyRuntime, SharedRuntimeState shared) : this(shared) { if (proxyRuntime == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("proxyRuntime"); } _proxyRuntime = proxyRuntime; _instanceProvider = new CallbackInstanceProvider(); _channelDispatcher = new ChannelDispatcher(shared); _instanceContextProvider = InstanceContextProviderBase.GetProviderForMode(InstanceContextMode.PerSession, this); Fx.Assert(!shared.IsOnServer, "Client constructor called on server?"); } private DispatchRuntime(SharedRuntimeState shared) { _shared = shared; _operations = new OperationCollection(this); _synchronizationContext = ThreadBehavior.GetCurrentSynchronizationContext(); _automaticInputSessionShutdown = true; _unhandled = new DispatchOperation(this, "*", MessageHeaders.WildcardAction, MessageHeaders.WildcardAction); _unhandled.InternalFormatter = MessageOperationFormatter.Instance; _unhandled.InternalInvoker = new UnhandledActionInvoker(this); } public IInstanceContextProvider InstanceContextProvider { get { return _instanceContextProvider; } set { if (value == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("value")); } lock (this.ThisLock) { this.InvalidateRuntime(); _instanceContextProvider = value; } } } public ConcurrencyMode ConcurrencyMode { get { return _concurrencyMode; } set { lock (this.ThisLock) { this.InvalidateRuntime(); _concurrencyMode = value; } } } public bool EnsureOrderedDispatch { get { return _ensureOrderedDispatch; } set { lock (this.ThisLock) { this.InvalidateRuntime(); _ensureOrderedDispatch = value; } } } public bool AutomaticInputSessionShutdown { get { return _automaticInputSessionShutdown; } set { lock (this.ThisLock) { this.InvalidateRuntime(); _automaticInputSessionShutdown = value; } } } public ChannelDispatcher ChannelDispatcher { get { return _channelDispatcher ?? _endpointDispatcher.ChannelDispatcher; } } public ClientRuntime CallbackClientRuntime { get { if (_proxyRuntime == null) { lock (this.ThisLock) { if (_proxyRuntime == null) { _proxyRuntime = new ClientRuntime(this, _shared); } } } return _proxyRuntime; } } public EndpointDispatcher EndpointDispatcher { get { return _endpointDispatcher; } } public IInstanceProvider InstanceProvider { get { return _instanceProvider; } set { lock (this.ThisLock) { this.InvalidateRuntime(); _instanceProvider = value; } } } public SynchronizedKeyedCollection<string, DispatchOperation> Operations { get { return _operations; } } public SynchronizationContext SynchronizationContext { get { return _synchronizationContext; } set { lock (this.ThisLock) { this.InvalidateRuntime(); _synchronizationContext = value; } } } public Type Type { get { return _type; } set { lock (this.ThisLock) { this.InvalidateRuntime(); _type = value; } } } public DispatchOperation UnhandledDispatchOperation { get { return _unhandled; } set { if (value == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("value"); } lock (this.ThisLock) { this.InvalidateRuntime(); _unhandled = value; } } } internal bool HasMatchAllOperation { get { return false; } } internal bool EnableFaults { get { if (this.IsOnServer) { ChannelDispatcher channelDispatcher = this.ChannelDispatcher; return (channelDispatcher != null) && channelDispatcher.EnableFaults; } else { return _shared.EnableFaults; } } } internal bool IsOnServer { get { return _shared.IsOnServer; } } internal bool ManualAddressing { get { if (this.IsOnServer) { ChannelDispatcher channelDispatcher = this.ChannelDispatcher; return (channelDispatcher != null) && channelDispatcher.ManualAddressing; } else { return _shared.ManualAddressing; } } } internal int MaxParameterInspectors { get { lock (this.ThisLock) { int max = 0; for (int i = 0; i < _operations.Count; i++) { max = System.Math.Max(max, _operations[i].ParameterInspectors.Count); } max = System.Math.Max(max, _unhandled.ParameterInspectors.Count); return max; } } } // Internal access to CallbackClientRuntime, but this one doesn't create on demand internal ClientRuntime ClientRuntime { get { return _proxyRuntime; } } internal object ThisLock { get { return _shared; } } internal DispatchOperationRuntime GetOperation(ref Message message) { ImmutableDispatchRuntime runtime = this.GetRuntime(); return runtime.GetOperation(ref message); } internal ImmutableDispatchRuntime GetRuntime() { ImmutableDispatchRuntime runtime = _runtime; if (runtime != null) { return runtime; } else { return GetRuntimeCore(); } } private ImmutableDispatchRuntime GetRuntimeCore() { lock (this.ThisLock) { if (_runtime == null) { _runtime = new ImmutableDispatchRuntime(this); } return _runtime; } } internal void InvalidateRuntime() { lock (this.ThisLock) { _shared.ThrowIfImmutable(); _runtime = null; } } internal void LockDownProperties() { _shared.LockDownProperties(); } internal SynchronizedCollection<T> NewBehaviorCollection<T>() { return new DispatchBehaviorCollection<T>(this); } internal class UnhandledActionInvoker : IOperationInvoker { private readonly DispatchRuntime _dispatchRuntime; public UnhandledActionInvoker(DispatchRuntime dispatchRuntime) { _dispatchRuntime = dispatchRuntime; } public object[] AllocateInputs() { return new object[1]; } public Task<object> InvokeAsync(object instance, object[] inputs, out object[] outputs) { outputs = EmptyArray<object>.Allocate(0); Message message = inputs[0] as Message; if (message == null) { return null; } string action = message.Headers.Action; FaultCode code = FaultCode.CreateSenderFaultCode(AddressingStrings.ActionNotSupported, message.Version.Addressing.Namespace); string reasonText = string.Format(SRServiceModel.SFxNoEndpointMatchingContract, action); FaultReason reason = new FaultReason(reasonText); FaultException exception = new FaultException(reason, code); ErrorBehavior.ThrowAndCatch(exception); ServiceChannel serviceChannel = OperationContext.Current.InternalServiceChannel; OperationContext.Current.OperationCompleted += delegate (object sender, EventArgs e) { ChannelDispatcher channelDispatcher = _dispatchRuntime.ChannelDispatcher; if (!channelDispatcher.HandleError(exception) && serviceChannel.HasSession) { try { serviceChannel.Close(ChannelHandler.CloseAfterFaultTimeout); } catch (Exception ex) { if (Fx.IsFatal(ex)) { throw; } channelDispatcher.HandleError(ex); } } }; if (_dispatchRuntime._shared.EnableFaults) { MessageFault fault = MessageFault.CreateFault(code, reason, action); return Task.FromResult((object)Message.CreateMessage(message.Version, fault, message.Version.Addressing.DefaultFaultAction)); } else { OperationContext.Current.RequestContext.Close(); OperationContext.Current.RequestContext = null; return Task.FromResult((object)null); } } public IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotImplementedException()); } public object InvokeEnd(object instance, out object[] outputs, IAsyncResult result) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotImplementedException()); } } internal class DispatchBehaviorCollection<T> : SynchronizedCollection<T> { private DispatchRuntime _outer; internal DispatchBehaviorCollection(DispatchRuntime outer) : base(outer.ThisLock) { _outer = outer; } protected override void ClearItems() { _outer.InvalidateRuntime(); base.ClearItems(); } protected override void InsertItem(int index, T item) { if (item == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("item"); } _outer.InvalidateRuntime(); base.InsertItem(index, item); } protected override void RemoveItem(int index) { _outer.InvalidateRuntime(); base.RemoveItem(index); } protected override void SetItem(int index, T item) { if (item == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("item"); } _outer.InvalidateRuntime(); base.SetItem(index, item); } } internal class OperationCollection : SynchronizedKeyedCollection<string, DispatchOperation> { private DispatchRuntime _outer; internal OperationCollection(DispatchRuntime outer) : base(outer.ThisLock) { _outer = outer; } protected override void ClearItems() { _outer.InvalidateRuntime(); base.ClearItems(); } protected override string GetKeyForItem(DispatchOperation item) { return item.Name; } protected override void InsertItem(int index, DispatchOperation item) { if (item == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("item"); } if (item.Parent != _outer) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(SRServiceModel.SFxMismatchedOperationParent); } _outer.InvalidateRuntime(); base.InsertItem(index, item); } protected override void RemoveItem(int index) { _outer.InvalidateRuntime(); base.RemoveItem(index); } protected override void SetItem(int index, DispatchOperation item) { if (item == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("item"); } if (item.Parent != _outer) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(SRServiceModel.SFxMismatchedOperationParent); } _outer.InvalidateRuntime(); base.SetItem(index, item); } } private class CallbackInstanceProvider : IInstanceProvider { object IInstanceProvider.GetInstance(InstanceContext instanceContext) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SRServiceModel.SFxCannotActivateCallbackInstace)); } object IInstanceProvider.GetInstance(InstanceContext instanceContext, Message message) { throw TraceUtility.ThrowHelperError(new InvalidOperationException(SRServiceModel.SFxCannotActivateCallbackInstace), message); } void IInstanceProvider.ReleaseInstance(InstanceContext instanceContext, object instance) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SRServiceModel.SFxCannotActivateCallbackInstace)); } } } }