| File: System\ServiceModel\Dispatcher\ClientRuntime.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.Collections.Generic; using System.ComponentModel; using System.Collections.ObjectModel; using System.Diagnostics.CodeAnalysis; using System.Net; using System.Runtime; using System.ServiceModel.Channels; using System.ServiceModel.Security; using System.Xml; namespace System.ServiceModel.Dispatcher { [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Compat", Justification = "Compat is an accepted abbreviation")] [EditorBrowsable(EditorBrowsableState.Never)] public class ClientRuntimeCompatBase { internal ClientRuntimeCompatBase() { } [EditorBrowsable(EditorBrowsableState.Never)] [Obsolete("This API supports the .NET Framework infrastructure and is not intended to be used directly from your code.", true)] public IList<IClientMessageInspector> MessageInspectors { get { return _messageInspectors; } } [EditorBrowsable(EditorBrowsableState.Never)] [Obsolete("This API supports the .NET Framework infrastructure and is not intended to be used directly from your code.", true)] public KeyedCollection<string, ClientOperation> Operations { get { return _compatOperations; } } internal SynchronizedCollection<IClientMessageInspector> _messageInspectors; internal SynchronizedKeyedCollection<string, ClientOperation> _operations; internal KeyedCollection<string, ClientOperation> _compatOperations; } public sealed class ClientRuntime : ClientRuntimeCompatBase { private bool _addTransactionFlowProperties = true; private Type _callbackProxyType; private ProxyBehaviorCollection<IChannelInitializer> _channelInitializers; private string _contractNamespace; private Type _contractProxyType; private IdentityVerifier _identityVerifier; private ProxyBehaviorCollection<IInteractiveChannelInitializer> _interactiveChannelInitializers; private IClientOperationSelector _operationSelector; private ImmutableClientRuntime _runtime; private bool _useSynchronizationContext = true; private Uri _via; private SharedRuntimeState _shared; private int _maxFaultSize; private bool _messageVersionNoneFaultsEnabled; internal ClientRuntime(DispatchRuntime dispatchRuntime, SharedRuntimeState shared) : this(dispatchRuntime.EndpointDispatcher.ContractName, dispatchRuntime.EndpointDispatcher.ContractNamespace, shared) { DispatchRuntime = dispatchRuntime ?? throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(dispatchRuntime)); _shared = shared; Fx.Assert(shared.IsOnServer, "Server constructor called on client?"); } internal ClientRuntime(string contractName, string contractNamespace) : this(contractName, contractNamespace, new SharedRuntimeState(false)) { Fx.Assert(!_shared.IsOnServer, "Client constructor called on server?"); } private ClientRuntime(string contractName, string contractNamespace, SharedRuntimeState shared) { ContractName = contractName; _contractNamespace = contractNamespace; _shared = shared; OperationCollection operations = new OperationCollection(this); this._operations = operations; _compatOperations = new OperationCollectionWrapper(operations); _channelInitializers = new ProxyBehaviorCollection<IChannelInitializer>(this); _messageInspectors = new ProxyBehaviorCollection<IClientMessageInspector>(this); _interactiveChannelInitializers = new ProxyBehaviorCollection<IInteractiveChannelInitializer>(this); UnhandledClientOperation = new ClientOperation(this, "*", MessageHeaders.WildcardAction, MessageHeaders.WildcardAction); UnhandledClientOperation.InternalFormatter = new MessageOperationFormatter(); _maxFaultSize = TransportDefaults.MaxFaultSize; } internal bool AddTransactionFlowProperties { get { return _addTransactionFlowProperties; } set { lock (ThisLock) { InvalidateRuntime(); _addTransactionFlowProperties = value; } } } public Type CallbackClientType { get { return _callbackProxyType; } set { lock (ThisLock) { InvalidateRuntime(); _callbackProxyType = value; } } } public SynchronizedCollection<IChannelInitializer> ChannelInitializers { get { return _channelInitializers; } } public string ContractName { get; } public string ContractNamespace { get { return _contractNamespace; } } public Type ContractClientType { get { return _contractProxyType; } set { lock (ThisLock) { InvalidateRuntime(); _contractProxyType = value; } } } internal IdentityVerifier IdentityVerifier { get { if (_identityVerifier == null) { _identityVerifier = IdentityVerifier.CreateDefault(); } return _identityVerifier; } set { InvalidateRuntime(); _identityVerifier = value ?? throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(value)); } } public Uri Via { get { return _via; } set { lock (ThisLock) { InvalidateRuntime(); _via = value; } } } public bool ValidateMustUnderstand { get { return _shared.ValidateMustUnderstand; } set { lock (ThisLock) { InvalidateRuntime(); _shared.ValidateMustUnderstand = value; } } } public bool MessageVersionNoneFaultsEnabled { get { return _messageVersionNoneFaultsEnabled; } set { InvalidateRuntime(); _messageVersionNoneFaultsEnabled = value; } } public DispatchRuntime DispatchRuntime { get; private set; } public DispatchRuntime CallbackDispatchRuntime { get { if (DispatchRuntime == null) { DispatchRuntime = new DispatchRuntime(this, _shared); } return DispatchRuntime; } } internal bool EnableFaults { get { if (IsOnServer) { return DispatchRuntime.EnableFaults; } else { return _shared.EnableFaults; } } set { lock (ThisLock) { if (IsOnServer) { string text = SRP.SFxSetEnableFaultsOnChannelDispatcher0; throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(text)); } else { InvalidateRuntime(); _shared.EnableFaults = value; } } } } public SynchronizedCollection<IInteractiveChannelInitializer> InteractiveChannelInitializers { get { return _interactiveChannelInitializers; } } public int MaxFaultSize { get { return _maxFaultSize; } set { InvalidateRuntime(); _maxFaultSize = value; } } internal bool IsOnServer { get { return _shared.IsOnServer; } } public bool ManualAddressing { get { if (IsOnServer) { return DispatchRuntime.ManualAddressing; } else { return _shared.ManualAddressing; } } set { lock (ThisLock) { if (IsOnServer) { string text = SRP.SFxSetManualAddressingOnChannelDispatcher0; throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(text)); } else { InvalidateRuntime(); _shared.ManualAddressing = value; } } } } internal int MaxParameterInspectors { get { lock (ThisLock) { int max = 0; for (int i = 0; i < _operations.Count; i++) { max = System.Math.Max(max, _operations[i].ParameterInspectors.Count); } return max; } } } public ICollection<IClientMessageInspector> ClientMessageInspectors { get { return MessageInspectors; } } [EditorBrowsable(EditorBrowsableState.Never)] public new SynchronizedCollection<IClientMessageInspector> MessageInspectors { get { return _messageInspectors; } } public ICollection<ClientOperation> ClientOperations { get { return Operations; } } [EditorBrowsable(EditorBrowsableState.Never)] public new SynchronizedKeyedCollection<string, ClientOperation> Operations { get { return _operations; } } public IClientOperationSelector OperationSelector { get { return _operationSelector; } set { lock (ThisLock) { InvalidateRuntime(); _operationSelector = value; } } } internal object ThisLock { get { return _shared; } } public ClientOperation UnhandledClientOperation { get; } internal bool UseSynchronizationContext { get { return _useSynchronizationContext; } set { lock (ThisLock) { InvalidateRuntime(); _useSynchronizationContext = value; } } } internal T[] GetArray<T>(SynchronizedCollection<T> collection) { lock (collection.SyncRoot) { if (collection.Count == 0) { return Array.Empty<T>(); } else { T[] array = new T[collection.Count]; collection.CopyTo(array, 0); return array; } } } internal ImmutableClientRuntime GetRuntime() { lock (ThisLock) { if (_runtime == null) { _runtime = new ImmutableClientRuntime(this); } return _runtime; } } internal void InvalidateRuntime() { lock (ThisLock) { _shared.ThrowIfImmutable(); _runtime = null; } } internal void LockDownProperties() { _shared.LockDownProperties(); } internal SynchronizedCollection<T> NewBehaviorCollection<T>() { return new ProxyBehaviorCollection<T>(this); } internal bool IsFault(ref Message reply) { if (reply == null) { return false; } if (reply.IsFault) { return true; } if (MessageVersionNoneFaultsEnabled && IsMessageVersionNoneFault(ref reply, MaxFaultSize)) { return true; } return false; } internal static bool IsMessageVersionNoneFault(ref Message message, int maxFaultSize) { if (message.Version != MessageVersion.None || message.IsEmpty) { return false; } if (message.Properties.ContainsKey("_System.Net.HttpStatusCode")) { HttpStatusCode statusCode = (HttpStatusCode)message.Properties["_System.Net.HttpStatusCode"]; if (statusCode != HttpStatusCode.InternalServerError) { return false; } } using (MessageBuffer buffer = message.CreateBufferedCopy(maxFaultSize)) { message.Close(); message = buffer.CreateMessage(); using (Message copy = buffer.CreateMessage()) { using (XmlDictionaryReader reader = copy.GetReaderAtBodyContents()) { return reader.IsStartElement(XD.MessageDictionary.Fault, MessageVersion.None.Envelope.DictionaryNamespace); } } } } internal class ProxyBehaviorCollection<T> : SynchronizedCollection<T> { private ClientRuntime _outer; internal ProxyBehaviorCollection(ClientRuntime 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(nameof(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(nameof(item)); } _outer.InvalidateRuntime(); base.SetItem(index, item); } } internal class OperationCollection : SynchronizedKeyedCollection<string, ClientOperation> { private ClientRuntime _outer; internal OperationCollection(ClientRuntime outer) : base(outer.ThisLock) { _outer = outer; } protected override void ClearItems() { _outer.InvalidateRuntime(); base.ClearItems(); } protected override string GetKeyForItem(ClientOperation item) { return item.Name; } protected override void InsertItem(int index, ClientOperation item) { if (item == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(item)); } if (item.Parent != _outer) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(SRP.SFxMismatchedOperationParent); } _outer.InvalidateRuntime(); base.InsertItem(index, item); } protected override void RemoveItem(int index) { _outer.InvalidateRuntime(); base.RemoveItem(index); } protected override void SetItem(int index, ClientOperation item) { if (item == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(item)); } if (item.Parent != _outer) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(SRP.SFxMismatchedOperationParent); } _outer.InvalidateRuntime(); base.SetItem(index, item); } internal void InternalClearItems() { ClearItems(); } internal string InternalGetKeyForItem(ClientOperation item) { return GetKeyForItem(item); } internal void InternalInsertItem(int index, ClientOperation item) { InsertItem(index, item); } internal void InternalRemoveItem(int index) { RemoveItem(index); } internal void InternalSetItem(int index, ClientOperation item) { SetItem(index, item); } } internal class OperationCollectionWrapper : KeyedCollection<string, ClientOperation> { private OperationCollection _inner; internal OperationCollectionWrapper(OperationCollection inner) { _inner = inner; } protected override void ClearItems() { _inner.InternalClearItems(); } protected override string GetKeyForItem(ClientOperation item) { return _inner.InternalGetKeyForItem(item); } protected override void InsertItem(int index, ClientOperation item) { _inner.InternalInsertItem(index, item); } protected override void RemoveItem(int index) { _inner.InternalRemoveItem(index); } protected override void SetItem(int index, ClientOperation item) { _inner.InternalSetItem(index, item); } } } }