| File: FrameworkFork\System.ServiceModel\System\ServiceModel\Dispatcher\ChannelDispatcher.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.Globalization; using System.Runtime; using System.Runtime.Diagnostics; using System.ServiceModel.Channels; using System.Text; using System.Threading.Tasks; namespace System.ServiceModel.Dispatcher { public class ChannelDispatcher : ChannelDispatcherBase { private SynchronizedCollection<IChannelInitializer> _channelInitializers; private CommunicationObjectManager<IChannel> _channels; private EndpointDispatcherCollection _endpointDispatchers; private Collection<IErrorHandler> _errorHandlers; private EndpointDispatcherTable _filterTable; private bool _receiveContextEnabled; private readonly IChannelListener _listener = null; private ListenerHandler _listenerHandler; private int _maxTransactedBatchSize; private MessageVersion _messageVersion; private SynchronizedChannelCollection<IChannel> _pendingChannels; // app has not yet seen these. private bool _receiveSynchronously; private bool _sendAsynchronously; private int _maxPendingReceives; private bool _includeExceptionDetailInFaults; private bool _session = false; private SharedRuntimeState _shared; private IDefaultCommunicationTimeouts _timeouts = null; private TimeSpan _transactionTimeout; private bool _performDefaultCloseInput; private EventTraceActivity _eventTraceActivity; private ErrorBehavior _errorBehavior; internal ChannelDispatcher(SharedRuntimeState shared) { this.Initialize(shared); } private void Initialize(SharedRuntimeState shared) { _shared = shared; _endpointDispatchers = new EndpointDispatcherCollection(this); _channelInitializers = this.NewBehaviorCollection<IChannelInitializer>(); _channels = new CommunicationObjectManager<IChannel>(this.ThisLock); _pendingChannels = new SynchronizedChannelCollection<IChannel>(this.ThisLock); _errorHandlers = new Collection<IErrorHandler>(); _receiveSynchronously = false; _transactionTimeout = TimeSpan.Zero; _maxPendingReceives = 1; //Default maxpending receives is 1; if (_listener != null) { _listener.Faulted += new EventHandler(OnListenerFaulted); } } protected override TimeSpan DefaultCloseTimeout { get { if (_timeouts != null) { return _timeouts.CloseTimeout; } else { return ServiceDefaults.CloseTimeout; } } } protected override TimeSpan DefaultOpenTimeout { get { if (_timeouts != null) { return _timeouts.OpenTimeout; } else { return ServiceDefaults.OpenTimeout; } } } internal EndpointDispatcherTable EndpointDispatcherTable { get { return _filterTable; } } internal CommunicationObjectManager<IChannel> Channels { get { return _channels; } } public SynchronizedCollection<EndpointDispatcher> Endpoints { get { return _endpointDispatchers; } } public Collection<IErrorHandler> ErrorHandlers { get { return _errorHandlers; } } public MessageVersion MessageVersion { get { return _messageVersion; } set { _messageVersion = value; this.ThrowIfDisposedOrImmutable(); } } internal bool EnableFaults { get { return _shared.EnableFaults; } set { this.ThrowIfDisposedOrImmutable(); _shared.EnableFaults = value; } } internal bool IsOnServer { get { return _shared.IsOnServer; } } public bool ReceiveContextEnabled { get { return _receiveContextEnabled; } set { this.ThrowIfDisposedOrImmutable(); _receiveContextEnabled = value; } } internal bool BufferedReceiveEnabled { get; set; } public override IChannelListener Listener { get { return _listener; } } public int MaxTransactedBatchSize { get { return _maxTransactedBatchSize; } set { if (value < 0) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value", value, SRServiceModel.ValueMustBeNonNegative)); } this.ThrowIfDisposedOrImmutable(); _maxTransactedBatchSize = value; } } public bool ManualAddressing { get { return _shared.ManualAddressing; } set { this.ThrowIfDisposedOrImmutable(); _shared.ManualAddressing = value; } } internal SynchronizedChannelCollection<IChannel> PendingChannels { get { return _pendingChannels; } } public bool ReceiveSynchronously { get { return _receiveSynchronously; } set { this.ThrowIfDisposedOrImmutable(); _receiveSynchronously = value; } } public bool SendAsynchronously { get { return _sendAsynchronously; } set { this.ThrowIfDisposedOrImmutable(); _sendAsynchronously = value; } } public int MaxPendingReceives { get { return _maxPendingReceives; } set { this.ThrowIfDisposedOrImmutable(); _maxPendingReceives = value; } } public bool IncludeExceptionDetailInFaults { get { return _includeExceptionDetailInFaults; } set { lock (this.ThisLock) { this.ThrowIfDisposedOrImmutable(); _includeExceptionDetailInFaults = value; } } } internal IDefaultCommunicationTimeouts DefaultCommunicationTimeouts { get { return _timeouts; } } private void AbortPendingChannels() { lock (this.ThisLock) { for (int i = _pendingChannels.Count - 1; i >= 0; i--) { _pendingChannels[i].Abort(); } } } internal override void CloseInput(TimeSpan timeout) { // we have to perform some slightly convoluted logic here due to // backwards compat. We probably need an IAsyncChannelDispatcher // interface that has timeouts and async this.CloseInput(); if (_performDefaultCloseInput) { TimeoutHelper timeoutHelper = new TimeoutHelper(timeout); lock (this.ThisLock) { ListenerHandler handler = _listenerHandler; if (handler != null) { handler.CloseInput(timeoutHelper.RemainingTime()); } } if (!_session) { ListenerHandler handler = _listenerHandler; if (handler != null) { handler.Close(timeoutHelper.RemainingTime()); } } } } public override void CloseInput() { _performDefaultCloseInput = true; } private void OnListenerFaulted(object sender, EventArgs e) { this.Fault(); } internal bool HandleError(Exception error) { ErrorHandlerFaultInfo dummy = new ErrorHandlerFaultInfo(); return this.HandleError(error, ref dummy); } internal bool HandleError(Exception error, ref ErrorHandlerFaultInfo faultInfo) { ErrorBehavior behavior; lock (this.ThisLock) { if (_errorBehavior != null) { behavior = _errorBehavior; } else { behavior = new ErrorBehavior(this); } } if (behavior != null) { return behavior.HandleError(error, ref faultInfo); } else { return false; } } internal void InitializeChannel(IClientChannel channel) { this.ThrowIfDisposedOrNotOpen(); try { for (int i = 0; i < _channelInitializers.Count; ++i) { _channelInitializers[i].Initialize(channel); } } catch (Exception e) { if (Fx.IsFatal(e)) { throw; } throw DiagnosticUtility.ExceptionUtility.ThrowHelperCallback(e); } } internal SynchronizedCollection<T> NewBehaviorCollection<T>() { return new ChannelDispatcherBehaviorCollection<T>(this); } private void OnAddEndpoint(EndpointDispatcher endpoint) { lock (this.ThisLock) { endpoint.Attach(this); if (this.State == CommunicationState.Opened) { _filterTable.AddEndpoint(endpoint); } } } private void OnRemoveEndpoint(EndpointDispatcher endpoint) { lock (this.ThisLock) { if (this.State == CommunicationState.Opened) { _filterTable.RemoveEndpoint(endpoint); } endpoint.Detach(this); } } protected override void OnAbort() { if (_listener != null) { _listener.Abort(); } ListenerHandler handler = _listenerHandler; if (handler != null) { handler.Abort(); } this.AbortPendingChannels(); } protected override void OnClose(TimeSpan timeout) { TimeoutHelper timeoutHelper = new TimeoutHelper(timeout); if (_listener != null) { _listener.Close(timeoutHelper.RemainingTime()); } ListenerHandler handler = _listenerHandler; if (handler != null) { handler.Close(timeoutHelper.RemainingTime()); } this.AbortPendingChannels(); } protected override IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback callback, object state) { List<ICommunicationObject> list = new List<ICommunicationObject>(); if (_listener != null) { list.Add(_listener); } ListenerHandler handler = _listenerHandler; if (handler != null) { list.Add(handler); } return new CloseCollectionAsyncResult(timeout, callback, state, list); } protected override void OnEndClose(IAsyncResult result) { try { CloseCollectionAsyncResult.End(result); } finally { this.AbortPendingChannels(); } } protected override void OnClosed() { base.OnClosed(); } protected override void OnOpen(TimeSpan timeout) { ThrowIfNoMessageVersion(); if (_listener != null) { try { _listener.Open(timeout); } catch (InvalidOperationException e) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateOuterExceptionWithEndpointsInformation(e)); } } } protected internal override Task OnCloseAsync(TimeSpan timeout) { this.OnClose(timeout); return TaskHelpers.CompletedTask(); } protected internal override Task OnOpenAsync(TimeSpan timeout) { this.OnOpen(timeout); return TaskHelpers.CompletedTask(); } private InvalidOperationException CreateOuterExceptionWithEndpointsInformation(InvalidOperationException e) { string endpointContractNames = CreateContractListString(); if (String.IsNullOrEmpty(endpointContractNames)) { return new InvalidOperationException(string.Format(SRServiceModel.SFxChannelDispatcherUnableToOpen1, _listener.Uri), e); } else { return new InvalidOperationException(string.Format(SRServiceModel.SFxChannelDispatcherUnableToOpen2, _listener.Uri, endpointContractNames), e); } } internal string CreateContractListString() { const string OpenQuote = "\""; const string CloseQuote = "\""; const string Space = " "; Collection<string> namesSeen = new Collection<string>(); StringBuilder endpointContractNames = new StringBuilder(); lock (this.ThisLock) { foreach (EndpointDispatcher ed in this.Endpoints) { if (!namesSeen.Contains(ed.ContractName)) { if (endpointContractNames.Length > 0) { endpointContractNames.Append(CultureInfo.CurrentCulture.TextInfo.ListSeparator); endpointContractNames.Append(Space); } endpointContractNames.Append(OpenQuote); endpointContractNames.Append(ed.ContractName); endpointContractNames.Append(CloseQuote); namesSeen.Add(ed.ContractName); } } } return endpointContractNames.ToString(); } protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state) { ThrowIfNoMessageVersion(); if (_listener != null) { try { return _listener.BeginOpen(timeout, callback, state); } catch (InvalidOperationException e) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateOuterExceptionWithEndpointsInformation(e)); } } else { return new CompletedAsyncResult(callback, state); } } protected override void OnEndOpen(IAsyncResult result) { if (_listener != null) { try { _listener.EndOpen(result); } catch (InvalidOperationException e) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateOuterExceptionWithEndpointsInformation(e)); } } else { CompletedAsyncResult.End(result); } } protected override void OnOpening() { if (WcfEventSource.Instance.ListenerOpenStartIsEnabled()) { _eventTraceActivity = EventTraceActivity.GetFromThreadOrCreate(); WcfEventSource.Instance.ListenerOpenStart(_eventTraceActivity, (this.Listener != null) ? this.Listener.Uri.ToString() : string.Empty, Guid.Empty); // Desktop: (this.host != null && host.EventTraceActivity != null) ? this.host.EventTraceActivity.ActivityId : Guid.Empty); } base.OnOpening(); } protected override void OnOpened() { base.OnOpened(); if (WcfEventSource.Instance.ListenerOpenStopIsEnabled()) { WcfEventSource.Instance.ListenerOpenStop(_eventTraceActivity); _eventTraceActivity = null; // clear this since we don't need this anymore. } _errorBehavior = new ErrorBehavior(this); _filterTable = new EndpointDispatcherTable(this.ThisLock); for (int i = 0; i < _endpointDispatchers.Count; i++) { EndpointDispatcher endpoint = _endpointDispatchers[i]; // Force a build of the runtime to catch any unexpected errors before we are done opening. // Lock down the DispatchRuntime. endpoint.DispatchRuntime.LockDownProperties(); _filterTable.AddEndpoint(endpoint); } IListenerBinder binder = ListenerBinder.GetBinder(_listener, _messageVersion); _listenerHandler = new ListenerHandler(binder, this, _timeouts); _listenerHandler.Open(); // This never throws, which is why it's ok for it to happen in OnOpened } internal void ProvideFault(Exception e, FaultConverter faultConverter, ref ErrorHandlerFaultInfo faultInfo) { ErrorBehavior behavior; lock (this.ThisLock) { if (_errorBehavior != null) { behavior = _errorBehavior; } else { behavior = new ErrorBehavior(this); } } behavior.ProvideFault(e, faultConverter, ref faultInfo); } internal new void ThrowIfDisposedOrImmutable() { base.ThrowIfDisposedOrImmutable(); _shared.ThrowIfImmutable(); } private void ThrowIfNoMessageVersion() { if (_messageVersion == null) { Exception error = new InvalidOperationException(SRServiceModel.SFxChannelDispatcherNoMessageVersion); throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(error); } } internal class EndpointDispatcherCollection : SynchronizedCollection<EndpointDispatcher> { private ChannelDispatcher _owner; internal EndpointDispatcherCollection(ChannelDispatcher owner) : base(owner.ThisLock) { _owner = owner; } protected override void ClearItems() { foreach (EndpointDispatcher item in this.Items) { _owner.OnRemoveEndpoint(item); } base.ClearItems(); } protected override void InsertItem(int index, EndpointDispatcher item) { if (item == null) throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("item"); _owner.OnAddEndpoint(item); base.InsertItem(index, item); } protected override void RemoveItem(int index) { EndpointDispatcher item = this.Items[index]; base.RemoveItem(index); _owner.OnRemoveEndpoint(item); } protected override void SetItem(int index, EndpointDispatcher item) { Exception error = new InvalidOperationException(SRServiceModel.SFxCollectionDoesNotSupportSet0); throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(error); } } internal class ChannelDispatcherBehaviorCollection<T> : SynchronizedCollection<T> { private ChannelDispatcher _outer; internal ChannelDispatcherBehaviorCollection(ChannelDispatcher outer) : base(outer.ThisLock) { _outer = outer; } protected override void ClearItems() { _outer.ThrowIfDisposedOrImmutable(); base.ClearItems(); } protected override void InsertItem(int index, T item) { if (item == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("item"); } _outer.ThrowIfDisposedOrImmutable(); base.InsertItem(index, item); } protected override void RemoveItem(int index) { _outer.ThrowIfDisposedOrImmutable(); base.RemoveItem(index); } protected override void SetItem(int index, T item) { if (item == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("item"); } _outer.ThrowIfDisposedOrImmutable(); base.SetItem(index, item); } } } }