< Summary - CoreWCF Coverage — PR #1766

Information
Class: CoreWCF.Dispatcher.ChannelHandler
Assembly: CoreWCF.Primitives
File(s): /home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.Primitives/src/CoreWCF/Dispatcher/ChannelHandler.cs
Line coverage
74%
Covered lines: 297
Uncovered lines: 101
Coverable lines: 398
Total lines: 1067
Line coverage: 74.6%
Branch coverage
68%
Covered branches: 137
Total branches: 200
Branch coverage: 68.5%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

File(s)

/home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.Primitives/src/CoreWCF/Dispatcher/ChannelHandler.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3
 4using System;
 5using System.Diagnostics;
 6using System.Globalization;
 7using System.Threading.Tasks;
 8using System.Xml;
 9using CoreWCF.Channels;
 10using CoreWCF.Configuration;
 11using CoreWCF.Description;
 12using CoreWCF.Diagnostics;
 13using CoreWCF.Runtime;
 14using SessionIdleManager = CoreWCF.Channels.ServiceChannel.SessionIdleManager;
 15
 16namespace CoreWCF.Dispatcher
 17{
 18    internal class ChannelHandler : IServiceChannelDispatcher, IDefaultCommunicationTimeouts
 19    {
 020        public static readonly TimeSpan CloseAfterFaultTimeout = TimeSpan.FromSeconds(10);
 21        public const string MessageBufferPropertyName = "_RequestMessageBuffer_";
 22        private ServiceChannel _channel;
 23        private bool _doneReceiving;
 24        private readonly ServiceDispatcher _serviceDispatcher;
 25        private readonly MessageVersion _messageVersion;
 26        private readonly bool _isManualAddressing;
 27        private readonly IChannelBinder _binder;
 28        private readonly ServiceThrottle _throttle;
 29        private readonly bool _wasChannelThrottled;
 30        private readonly DuplexChannelBinder _duplexBinder;
 31        private readonly ServiceHostBase _host;
 32        private readonly bool _hasSession;
 33        private readonly bool _isConcurrent;
 34        private readonly SessionIdleManager _idleManager;
 35        private readonly SessionOpenNotification _sessionOpenNotification;
 36        private bool _needToCreateSessionOpenNotificationMessage;
 37        //private RequestInfo _requestInfo;
 38        private bool _isChannelTerminated;
 39        private bool _shouldRejectMessageWithOnOpenActionHeader;
 40        private RequestContext _replied;
 41        private readonly bool _incrementedActivityCountInConstructor;
 42        private readonly AsyncManualResetEvent _asyncManualResetEvent;
 43        private bool _openCalled;
 44        private AsyncLock _thisLock;
 45
 231846        internal ChannelHandler(MessageVersion messageVersion, IChannelBinder binder, ServiceThrottle throttle,
 231847             ServiceDispatcher serviceDispatcher, bool wasChannelThrottled, SessionIdleManager idleManager)
 48        {
 231849            ChannelDispatcher channelDispatcher = serviceDispatcher.ChannelDispatcher;
 231850            _serviceDispatcher = serviceDispatcher;
 231851            _messageVersion = messageVersion;
 231852            _isManualAddressing = channelDispatcher.ManualAddressing;
 231853            _binder = binder;
 231854            _throttle = throttle;
 231855            _wasChannelThrottled = wasChannelThrottled;
 231856            _host = channelDispatcher.Host;
 231857            _duplexBinder = binder as DuplexChannelBinder;
 231858            _hasSession = binder.HasSession;
 231859            _isConcurrent = ConcurrencyBehavior.IsConcurrent(channelDispatcher, _hasSession);
 231860            _thisLock = new AsyncLock();
 61
 62            // TODO: Work out if MultipleReceiveBinder is necessary
 63            //if (channelDispatcher.MaxPendingReceives > 1)
 64            //{
 65            //    // We need to preserve order if the ChannelHandler is not concurrent.
 66            //    this.binder = new MultipleReceiveBinder(
 67            //        this.binder,
 68            //        channelDispatcher.MaxPendingReceives,
 69            //        !this.isConcurrent);
 70            //}
 71
 231872            _idleManager = idleManager;
 73
 231874            if (_binder.HasSession)
 75            {
 8776                _sessionOpenNotification = _binder.Channel.GetProperty<SessionOpenNotification>();
 8777                _needToCreateSessionOpenNotificationMessage = _sessionOpenNotification != null && _sessionOpenNotificati
 78            }
 79
 80            //_requestInfo = new RequestInfo(this);
 81
 82            // TODO: Wire up lifetime management in place of listener state
 83            //if (this.listener.State == CommunicationState.Opened)
 84            //{
 231885            _serviceDispatcher.ChannelDispatcher.Channels.IncrementActivityCount();
 231886            _incrementedActivityCountInConstructor = true;
 87            //}
 231888            _asyncManualResetEvent = new AsyncManualResetEvent();
 231889        }
 90
 91        internal IServiceChannelDispatcher GetDispatcher()
 92        {
 231893            return _binder;
 94        }
 95
 96        internal async Task OpenAsync()
 97        {
 231898            _binder.SetNextDispatcher(this);
 231899            Exception exception = null;
 100            try
 101            {
 2318102                await _binder.Channel.OpenAsync();
 2318103            }
 0104            catch (Exception e)
 105            {
 0106                if (Fx.IsFatal(e))
 107                {
 0108                    throw;
 109                }
 0110                exception = e;
 0111            }
 112
 2318113            if (exception != null)
 114            {
 115                //if (DiagnosticUtility.ShouldTraceWarning)
 116                //{
 117                //    TraceUtility.TraceEvent(System.Diagnostics.TraceEventType.Warning,
 118                //        TraceCode.FailedToOpenIncomingChannel,
 119                //        SR.GetString(SR.TraceCodeFailedToOpenIncomingChannel));
 120                //}
 0121                if ((_throttle != null) && _hasSession)
 122                {
 0123                    _throttle.DeactivateChannel();
 124                }
 125
 0126                bool errorHandled = HandleError(exception);
 127
 128                //if (this.incrementedActivityCountInConstructor)
 129                //{
 130                //    this.listener.ChannelDispatcher.Channels.DecrementActivityCount();
 131                //}
 132
 0133                if (!errorHandled)
 134                {
 0135                    _binder.Channel.Abort();
 136                }
 137            }
 138            else
 139            {
 2318140                ReleasePump();
 2318141                _shouldRejectMessageWithOnOpenActionHeader = !_needToCreateSessionOpenNotificationMessage;
 2318142                if (_needToCreateSessionOpenNotificationMessage)
 143                {
 1144                    _needToCreateSessionOpenNotificationMessage = false;
 1145                    RequestContext requestContext = GetSessionOpenNotificationRequestContext();
 1146                    await HandleReceiveCompleteAsync(requestContext);
 1147                    HandleRequestAsync(requestContext);
 1148                }
 2318149                ReleasePump();
 150            }
 151
 2318152            _openCalled = true;
 2318153        }
 154
 0155        internal bool HasRegisterBeenCalled { get; set; }
 156
 157        internal InstanceContext InstanceContext
 158        {
 0159            get { return _channel?.InstanceContext; }
 160        }
 161
 2932162        internal ServiceThrottle InstanceContextServiceThrottle { get; set; }
 163
 164        private bool IsOpen
 165        {
 19166            get { return _binder.Channel.State == CommunicationState.Opened; }
 167        }
 168
 169        private EndpointAddress LocalAddress
 170        {
 171            get
 172            {
 1173                if (_binder != null)
 174                {
 1175                    if (_binder.Channel is IInputChannel input)
 176                    {
 1177                        return input.LocalAddress;
 178                    }
 179
 0180                    if (_binder.Channel is IReplyChannel reply)
 181                    {
 0182                        return reply.LocalAddress;
 183                    }
 184                }
 185
 0186                return null;
 187            }
 188        }
 189
 190        public async Task CloseBinderAsync()
 191        {
 192            try
 193            {
 3194                await _binder.Channel.CloseAsync();
 2195            }
 1196            catch (Exception e)
 197            {
 1198                if (Fx.IsFatal(e))
 199                {
 0200                    throw;
 201                }
 202
 1203                HandleError(e);
 1204            }
 3205        }
 206
 207        public void EnsureReceive()
 208        {
 2536209            _asyncManualResetEvent.Set();
 2536210        }
 211
 212        public Task DispatchAsync(Message message)
 213        {
 0214            RequestContext requestContext = _binder.CreateRequestContext(message);
 0215            return DispatchAsync(requestContext);
 216        }
 217
 218        public async Task DispatchAsync(RequestContext requestContext)
 219        {
 2685220            if (!_openCalled)
 221            {
 0222                throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.Format(SRCommon.CommunicationObject
 223            }
 224
 2685225            await TryAcquirePumpAsync();
 2685226            await HandleReceiveCompleteAsync(requestContext);
 2685227            if (requestContext == null)
 228            {
 128229                return;
 230            }
 231
 232            // Don't await handling the request to allow caller to start receving the next incoming message
 2557233            HandleRequestAsync(requestContext);
 2685234        }
 235
 236        private RequestContext GetSessionOpenNotificationRequestContext()
 237        {
 238            Fx.Assert(_sessionOpenNotification != null, "this.sessionOpenNotification should not be null.");
 1239            Message message = Message.CreateMessage(_binder.Channel.GetProperty<MessageVersion>() ?? _messageVersion, Op
 240            Fx.Assert(LocalAddress != null, "this.LocalAddress should not be null.");
 1241            message.Headers.To = LocalAddress.Uri;
 1242            _sessionOpenNotification.UpdateMessageProperties(message.Properties);
 1243            return _binder.CreateRequestContext(message);
 244        }
 245
 246        private async void HandleRequestAsync(RequestContext request)
 247        {
 2558248            if (request == null)
 249            {
 250                // channel EOF, stop receiving
 0251                return;
 252            }
 253
 2558254            var requestInfo = new RequestInfo(this);
 255
 256            //ServiceModelActivity activity = DiagnosticUtility.ShouldUseActivity ? TraceUtility.ExtractActivity(request
 257
 258            //using (ServiceModelActivity.BoundOperation(activity))
 259            //{
 2558260            if (HandleRequestAsReply(request))
 261            {
 1262                ReleasePump();
 1263                return;
 264            }
 265
 2557266            if (_isChannelTerminated)
 267            {
 0268                ReleasePump();
 0269                await ReplyChannelTerminatedAsync(request, requestInfo);
 0270                return;
 271            }
 272
 2557273            requestInfo.RequestContext = request;
 274
 2557275            await TryAcquireCallThrottleAsync(request);
 276
 277            Fx.Assert(!requestInfo.ChannelHandlerOwnsCallThrottle, "ChannelHandler.HandleRequest: this.requestInfo.Chann
 278
 2557279            requestInfo.ChannelHandlerOwnsCallThrottle = true;
 280
 2557281            if (!await TryRetrievingInstanceContextAsync(request, requestInfo))
 282            {
 283                //Would have replied and close the request.
 18284                return;
 285            }
 286
 2539287            requestInfo.Channel.CompletedIOOperation();
 288
 289            //Only acquire InstanceContext throttle if one doesnt already exist.
 2539290            await TryAcquireThrottleAsync(request, requestInfo.ExistingInstanceContext == null);
 291            Fx.Assert(!requestInfo.ChannelHandlerOwnsInstanceContextThrottle, "ChannelHandler.HandleRequest: this.reques
 2539292            requestInfo.ChannelHandlerOwnsInstanceContextThrottle = (requestInfo.ExistingInstanceContext == null);
 293
 2539294            await DispatchAndReleasePumpAsync(request, true, requestInfo);
 295            //}
 2558296        }
 297
 298        private async Task DispatchAndReleasePumpAsync(RequestContext request, bool cleanThread, RequestInfo requestInfo
 299        {
 2539300            OperationContext currentOperationContext = null;
 2539301            ServiceChannel channel = requestInfo.Channel;
 2539302            EndpointDispatcher endpoint = requestInfo.Endpoint;
 2539303            bool releasedPump = false;
 304
 305            try
 306            {
 2539307                DispatchRuntime dispatchBehavior = requestInfo.DispatchRuntime;
 308
 2539309                if (channel == null || dispatchBehavior == null)
 310                {
 311                    Fx.Assert("System.ServiceModel.Dispatcher.ChannelHandler.Dispatch(): (channel == null || dispatchBeh
 0312                    return;
 313                }
 314
 315                Message message;
 316
 317                //EventTraceActivity eventTraceActivity = TraceDispatchMessageStart(request.RequestMessage);
 2539318                message = request.RequestMessage;
 319
 2539320                DispatchOperationRuntime operation = dispatchBehavior.GetOperation(ref message);
 2538321                if (operation == null)
 322                {
 323                    Fx.Assert("ChannelHandler.Dispatch (operation == null)");
 0324                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(string.Forma
 325                }
 326
 2538327                if (_shouldRejectMessageWithOnOpenActionHeader && message.Headers.Action == OperationDescription.Session
 328                {
 0329                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format(SR
 330                }
 331
 332                //if (MessageLogger.LoggingEnabled)
 333                //{
 334                //    MessageLogger.LogMessage(ref message, (operation.IsOneWay ? MessageLoggingSource.ServiceLevelRecei
 335                //}
 336
 2538337                if (operation.IsTerminating && _hasSession)
 338                {
 4339                    _isChannelTerminated = true;
 340                }
 341
 342                bool hasOperationContextBeenSet;
 2538343                if (currentOperationContext != null)
 344                {
 0345                    hasOperationContextBeenSet = true;
 0346                    currentOperationContext.ReInit(request, message, channel);
 347                }
 348                else
 349                {
 2538350                    hasOperationContextBeenSet = false;
 2538351                    currentOperationContext = new OperationContext(request, message, channel, _host);
 352                }
 353
 2538354                if (currentOperationContext.EndpointDispatcher == null && _serviceDispatcher != null)
 355                {
 2538356                    currentOperationContext.EndpointDispatcher = endpoint;
 357                }
 358
 2538359                var rpc = new MessageRpc(request, message, operation, channel, _host,
 2538360                    this, cleanThread, currentOperationContext, requestInfo.ExistingInstanceContext);
 361
 362                //TraceUtility.MessageFlowAtMessageReceived(message, currentOperationContext, eventTraceActivity, true);
 363
 364                // passing responsibility for call throttle to MessageRpc
 365                // (MessageRpc implicitly owns this throttle once it's created)
 2538366                requestInfo.ChannelHandlerOwnsCallThrottle = false;
 367                // explicitly passing responsibility for instance throttle to MessageRpc
 2538368                rpc.MessageRpcOwnsInstanceContextThrottle = requestInfo.ChannelHandlerOwnsInstanceContextThrottle;
 2538369                requestInfo.ChannelHandlerOwnsInstanceContextThrottle = false;
 370
 371                // These need to happen before Dispatch but after accessing any ChannelHandler
 372                // state, because we go multi-threaded after this
 2538373                ReleasePump();
 2538374                releasedPump = true;
 375
 2538376                await operation.Parent.DispatchAsync(rpc, hasOperationContextBeenSet);
 2538377            }
 1378            catch (Exception e)
 379            {
 1380                if (Fx.IsFatal(e))
 381                {
 0382                    throw;
 383                }
 384
 1385                await HandleErrorAsync(e, request, requestInfo, channel);
 386            }
 387            finally
 388            {
 2539389                if (!releasedPump)
 390                {
 1391                    ReleasePump();
 392                }
 393            }
 2539394        }
 395
 396        private async Task HandleReceiveCompleteAsync(RequestContext request)
 397        {
 398            try
 399            {
 2686400                if (_channel != null)
 401                {
 102402                    await _channel.HandleReceiveCompleteAsync(request);
 403                }
 404                else
 405                {
 2584406                    if (request == null && _hasSession)
 407                    {
 408                        bool close;
 3409                        await using (await _thisLock.TakeLockAsync())
 410                        {
 3411                            close = !_doneReceiving;
 3412                            _doneReceiving = true;
 413                        }
 414
 3415                        if (close)
 416                        {
 3417                            await CloseBinderAsync();
 418
 3419                            if (_idleManager != null)
 420                            {
 3421                                _idleManager.CancelTimer();
 422                            }
 423
 3424                            ServiceThrottle throttle = _throttle;
 3425                            if (throttle != null)
 426                            {
 0427                                throttle.DeactivateChannel();
 428                            }
 429                        }
 430                    }
 431                }
 2686432            }
 433            finally
 434            {
 2686435                if ((request == null) && _incrementedActivityCountInConstructor)
 436                {
 128437                    _serviceDispatcher.ChannelDispatcher.Channels.DecrementActivityCount();
 438                }
 439            }
 2686440        }
 441
 442        private bool HandleRequestAsReply(RequestContext request)
 443        {
 2558444            if (_duplexBinder != null)
 445            {
 89446                return _duplexBinder.HandleRequestAsReply(request.RequestMessage);
 447            }
 448
 2469449            return false;
 450        }
 451
 452        private async Task EnsureChannelAndEndpointAsync(RequestContext request, RequestInfo requestInfo)
 453        {
 2557454            requestInfo.Channel = _channel;
 455
 2557456            if (requestInfo.Channel == null)
 457            {
 458                (ServiceChannel serviceChannel, EndpointDispatcher endpoint, bool addressMatched) channelInfo;
 2534459                if (_hasSession)
 460                {
 85461                    channelInfo = await GetSessionChannelAsync(request.RequestMessage);
 462                }
 463                else
 464                {
 2449465                    channelInfo = await GetDatagramChannelAsync(request.RequestMessage);
 466                }
 467
 2518468                requestInfo.Channel = channelInfo.serviceChannel;
 2518469                requestInfo.Endpoint = channelInfo.endpoint;
 470
 2518471                if (requestInfo.Channel == null)
 472                {
 473                    // TODO: Enable UnknownMessageReceived handler
 474                    //this.host.RaiseUnknownMessageReceived(request.RequestMessage);
 2475                    if (channelInfo.addressMatched)
 476                    {
 2477                        await ReplyContractFilterDidNotMatchAsync(request, requestInfo);
 478                    }
 479                    else
 480                    {
 0481                        await ReplyAddressFilterDidNotMatchAsync(request, requestInfo);
 482                    }
 483                }
 484            }
 485            else
 486            {
 23487                requestInfo.Endpoint = requestInfo.Channel.EndpointDispatcher;
 488
 489                //For sessionful contracts, the InstanceContext throttle is not copied over to the channel
 490                //as we create the channel before acquiring the lock
 23491                if (InstanceContextServiceThrottle != null && requestInfo.Channel.InstanceContextServiceThrottle == null
 492                {
 0493                    requestInfo.Channel.InstanceContextServiceThrottle = InstanceContextServiceThrottle;
 494                }
 495            }
 496
 2541497            requestInfo.EndpointLookupDone = true;
 498
 2541499            if (requestInfo.Channel == null)
 500            {
 501                // SFx drops a message here
 2502                TraceUtility.TraceDroppedMessage(request.RequestMessage, requestInfo.Endpoint);
 2503                await request.CloseAsync();
 2504                return;
 505            }
 506
 2539507            if (requestInfo.Channel.HasSession)
 508            {
 106509                requestInfo.DispatchRuntime = requestInfo.Channel.DispatchRuntime;
 510            }
 511            else
 512            {
 2433513                requestInfo.DispatchRuntime = requestInfo.Endpoint.DispatchRuntime;
 514            }
 2541515        }
 516
 517        private async Task<(ServiceChannel serviceChannel, EndpointDispatcher endpoint, bool addressMatched)> GetDatagra
 518        {
 2433519            var endpoint = GetEndpointDispatcher(message, out var addressMatched);
 520
 2433521            if (endpoint == null)
 522            {
 0523                return (null, null, addressMatched);
 524            }
 525
 2433526            if (endpoint.DatagramChannel == null)
 527            {
 433528                await using (await _serviceDispatcher.ThisLock.TakeLockAsync())
 529                {
 433530                    if (endpoint.DatagramChannel == null)
 531                    {
 433532                        endpoint.DatagramChannel = new ServiceChannel(_binder, endpoint, _serviceDispatcher,
 433533                            _idleManager.UseIfNeeded(_binder, _serviceDispatcher.Binding.ReceiveTimeout));
 433534                        await InitializeServiceChannelAsync(endpoint.DatagramChannel);
 535                    }
 536                }
 537            }
 538
 2433539            return (endpoint.DatagramChannel, endpoint, addressMatched);
 2433540        }
 541
 542        private async Task<(ServiceChannel serviceChannel, EndpointDispatcher endpoint, bool addressMatched)> GetSession
 543        {
 85544            var addressMatched = false;
 545
 85546            if (_channel == null)
 547            {
 85548                await using (await _thisLock.TakeLockAsync())
 549                {
 85550                    if (_channel == null)
 551                    {
 85552                        var endpoint = GetEndpointDispatcher(message, out addressMatched);
 85553                        if (endpoint != null)
 554                        {
 83555                            _channel = new ServiceChannel(_binder, endpoint, _serviceDispatcher,
 83556                                _idleManager.UseIfNeeded(_binder, _serviceDispatcher.Binding.ReceiveTimeout));
 83557                            await InitializeServiceChannelAsync(_channel);
 558                        }
 559                    }
 560                }
 561            }
 562
 85563            return (_channel, _channel?.EndpointDispatcher, addressMatched);
 85564        }
 565
 566        private Task InitializeServiceChannelAsync(ServiceChannel channel)
 567        {
 516568            if (_wasChannelThrottled)
 569            {
 570                // Comment preserved from .NET Framework:
 571                // When the idle timeout was hit, the constructor of ServiceChannel will abort itself directly. So
 572                // the session throttle will not be released and thus lead to a service unavailablity.
 573                // Note that if the channel is already aborted, the next line "channel.ServiceThrottle = this.throttle;"
 574                // so we are not going to do any more work inside this method.
 575                // Ideally we should do a thorough refactoring work for this throttling issue. However, it's too risky. 
 576                // this in a whole release.
 577                // Note that the "wasChannelThrottled" boolean will only be true if we aquired the session throttle. So 
 578                // again here.
 0579                if (channel.Aborted && _throttle != null)
 580                {
 581                    // This line will release the "session" throttle.
 0582                    _throttle.DeactivateChannel();
 583                }
 584
 0585                channel.ServiceThrottle = _throttle;
 586            }
 587
 516588            if (InstanceContextServiceThrottle != null)
 589            {
 0590                channel.InstanceContextServiceThrottle = InstanceContextServiceThrottle;
 591            }
 592
 516593            ClientRuntime clientRuntime = channel.ClientRuntime;
 516594            if (clientRuntime != null)
 595            {
 516596                Type contractType = clientRuntime.ContractClientType;
 516597                Type callbackType = clientRuntime.CallbackClientType;
 598
 516599                if (contractType != null)
 600                {
 1601                    channel.Proxy = ServiceChannelFactory.CreateProxy(contractType, callbackType, MessageDirection.Outpu
 602                }
 603            }
 604
 516605            if (_serviceDispatcher != null)
 606            {
 516607                _serviceDispatcher.ChannelDispatcher.InitializeChannel((IClientChannel)channel.Proxy);
 608            }
 609
 516610            return ((IChannel)channel).OpenAsync();
 611        }
 612
 613        private void ProvideFault(Exception e, RequestInfo requestInfo, ref ErrorHandlerFaultInfo faultInfo)
 614        {
 19615            if (_serviceDispatcher != null)
 616            {
 19617                _serviceDispatcher.ChannelDispatcher.ProvideFault(e, requestInfo.Channel == null ? _binder.Channel.GetPr
 618            }
 619            // No client yet
 620            //else if (_channel != null)
 621            //{
 622            //    DispatchRuntime dispatchBehavior = _channel.ClientRuntime.CallbackDispatchRuntime;
 623            //    dispatchBehavior.ChannelDispatcher.ProvideFault(e, this.channel.GetProperty<FaultConverter>(), ref fau
 624            //}
 19625        }
 626
 627        internal bool HandleError(Exception e)
 628        {
 2629            ErrorHandlerFaultInfo dummy = new ErrorHandlerFaultInfo();
 2630            return HandleError(e, ref dummy);
 631        }
 632
 633        private bool HandleError(Exception e, ref ErrorHandlerFaultInfo faultInfo)
 634        {
 4635            if (e == null)
 636            {
 637                Fx.Assert(SR.SFxNonExceptionThrown);
 0638                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.SFxNonExcepti
 639            }
 4640            if (_serviceDispatcher != null)
 641            {
 4642                return _serviceDispatcher.ChannelDispatcher.HandleError(e, ref faultInfo);
 643            }
 644            // No client yet.
 645            //else if (this.channel != null)
 646            //{
 647            //    return this.channel.ClientRuntime.CallbackDispatchRuntime.ChannelDispatcher.HandleError(e, ref faultIn
 648            //}
 649            else
 650            {
 0651                return false;
 652            }
 653        }
 654
 655        private Task HandleErrorAsync(Exception e, RequestContext request, RequestInfo requestInfo, ServiceChannel chann
 656        {
 17657            var faultInfo = new ErrorHandlerFaultInfo(_messageVersion.Addressing.DefaultFaultAction);
 17658            return ProvideFaultAndReplyFailureAsync(request, requestInfo, e, faultInfo);
 659        }
 660
 661        private Task ReplyAddressFilterDidNotMatchAsync(RequestContext request, RequestInfo requestInfo)
 662        {
 0663            FaultCode code = FaultCode.CreateSenderFaultCode(AddressingStrings.DestinationUnreachable,
 0664                _messageVersion.Addressing.Namespace);
 0665            string reason = SR.Format(SR.SFxNoEndpointMatchingAddress, request.RequestMessage.Headers.To);
 666
 0667            return ReplyFailureAsync(request, requestInfo, code, reason);
 668        }
 669
 670        private Task ReplyContractFilterDidNotMatchAsync(RequestContext request, RequestInfo requestInfo)
 671        {
 672            // By default, the contract filter is just a filter over the set of initiating actions in
 673            // the contract, so we do error messages accordingly
 2674            AddressingVersion addressingVersion = _messageVersion.Addressing;
 2675            if (addressingVersion != AddressingVersion.None && request.RequestMessage.Headers.Action == null)
 676            {
 0677                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
 0678                    new MessageHeaderException(
 0679                    SR.Format(SR.SFxMissingActionHeader, addressingVersion.Namespace), AddressingStrings.Action, address
 680            }
 681            else
 682            {
 683                // some of this code is duplicated in DispatchRuntime.UnhandledActionInvoker
 684                // ideally both places would use FaultConverter and ActionNotSupportedException
 2685                FaultCode code = FaultCode.CreateSenderFaultCode(AddressingStrings.ActionNotSupported,
 2686                    _messageVersion.Addressing.Namespace);
 2687                string reason = SR.Format(SR.SFxNoEndpointMatchingContract, request.RequestMessage.Headers.Action);
 2688                return ReplyFailureAsync(request, requestInfo, code, reason, _messageVersion.Addressing.FaultAction);
 689            }
 690        }
 691
 692        private Task ReplyChannelTerminatedAsync(RequestContext request, RequestInfo requestInfo)
 693        {
 0694            FaultCode code = FaultCode.CreateSenderFaultCode(FaultCodeConstants.Codes.SessionTerminated,
 0695                FaultCodeConstants.Namespaces.NetDispatch);
 0696            string reason = SR.SFxChannelTerminated0;
 0697            string action = FaultCodeConstants.Actions.NetDispatcher;
 0698            Message fault = Message.CreateMessage(_messageVersion, code, reason, action);
 0699            return ReplyFailureAsync(request, requestInfo, fault, action, reason, code);
 700        }
 701
 702        private Task ReplyFailureAsync(RequestContext request, RequestInfo requestInfo, FaultCode code, string reason)
 703        {
 0704            string action = _messageVersion.Addressing.DefaultFaultAction;
 0705            return ReplyFailureAsync(request, requestInfo, code, reason, action);
 706        }
 707
 708        private Task ReplyFailureAsync(RequestContext request, RequestInfo requestInfo, FaultCode code, string reason, s
 709        {
 2710            Message fault = Message.CreateMessage(_messageVersion, code, reason, action);
 2711            return ReplyFailureAsync(request, requestInfo, fault, action, reason, code);
 712        }
 713
 714        private async Task ReplyFailureAsync(RequestContext request, RequestInfo requestInfo, Message fault, string acti
 715        {
 2716            FaultException exception = new FaultException(reason, code);
 2717            ErrorBehavior.ThrowAndCatch(exception);
 2718            ErrorHandlerFaultInfo faultInfo = new ErrorHandlerFaultInfo(action)
 2719            {
 2720                Fault = fault
 2721            };
 2722            faultInfo = await ProvideFaultAndReplyFailureAsync(request, requestInfo, exception, faultInfo);
 2723            HandleError(exception, ref faultInfo);
 2724        }
 725
 726        private async Task<ErrorHandlerFaultInfo> ProvideFaultAndReplyFailureAsync(RequestContext request, RequestInfo r
 727        {
 19728            bool requestMessageIsFault = false;
 729            try
 730            {
 19731                requestMessageIsFault = request.RequestMessage.IsFault;
 3732            }
 733            catch (Exception e)
 734            {
 16735                if (Fx.IsFatal(e))
 736                {
 0737                    throw;
 738                }
 739                // swallow it
 16740            }
 741
 19742            bool enableFaults = false;
 19743            if (_serviceDispatcher != null)
 744            {
 19745                enableFaults = _serviceDispatcher.ChannelDispatcher.EnableFaults;
 746            }
 747            // No client yet.
 748            //else if (this._channel != null && this._channel.IsClient)
 749            //{
 750            //    enableFaults = this._channel.ClientRuntime.EnableFaults;
 751            //}
 752
 19753            if ((!requestMessageIsFault) && enableFaults)
 754            {
 19755                ProvideFault(exception, requestInfo, ref faultInfo);
 19756                if (faultInfo.Fault != null)
 757                {
 19758                    Message reply = faultInfo.Fault;
 759                    try
 760                    {
 761                        try
 762                        {
 19763                            if (PrepareReply(request, reply))
 764                            {
 19765                                await request.ReplyAsync(reply);
 766                            }
 19767                        }
 768                        finally
 769                        {
 19770                            reply.Close();
 771                        }
 19772                    }
 0773                    catch (Exception e)
 774                    {
 0775                        if (Fx.IsFatal(e))
 776                        {
 0777                            throw;
 778                        }
 0779                        HandleError(e);
 0780                    }
 19781                }
 782            }
 783
 19784            return faultInfo;
 19785        }
 786
 787        /// <summary>
 788        /// Prepares a reply
 789        /// </summary>
 790        /// <param name="request">The request context to prepare</param>
 791        /// <param name="reply">The reply to prepare</param>
 792        /// <returns>True if channel is open and prepared reply should be sent; otherwise false.</returns>
 793        private bool PrepareReply(RequestContext request, Message reply)
 794        {
 795            // Ensure we only reply once (we may hit the same error multiple times)
 19796            if (_replied == request)
 797            {
 0798                return false;
 799            }
 800
 19801            _replied = request;
 802
 19803            bool canSendReply = true;
 804
 19805            Message requestMessage = null;
 806            try
 807            {
 19808                requestMessage = request.RequestMessage;
 3809            }
 810            catch (Exception e)
 811            {
 16812                if (Fx.IsFatal(e))
 813                {
 0814                    throw;
 815                }
 816                // swallow it
 16817            }
 19818            if (!ReferenceEquals(requestMessage, null))
 819            {
 3820                UniqueId requestID = null;
 821                try
 822                {
 3823                    requestID = requestMessage.Headers.MessageId;
 3824                }
 825#pragma warning disable CA1031 // Do not catch general exception types - intentionally swallowing this exception
 0826                catch (MessageHeaderException)
 827                {
 828                    // swallow it - we don't need to correlate the reply if the MessageId header is bad
 0829                }
 830#pragma warning restore CA1031 // Do not catch general exception types
 3831                if (!ReferenceEquals(requestID, null) && !_isManualAddressing)
 832                {
 2833                    RequestReplyCorrelator.PrepareReply(reply, requestID);
 834                }
 3835                if (!_hasSession && !_isManualAddressing)
 836                {
 837                    try
 838                    {
 1839                        canSendReply = RequestReplyCorrelator.AddressReply(reply, requestMessage);
 1840                    }
 841#pragma warning disable CA1031 // Do not catch general exception types - intentionally swallowing exception
 0842                    catch (MessageHeaderException)
 843                    {
 844                        // swallow it - we don't need to address the reply if the FaultTo header is bad
 0845                    }
 846#pragma warning restore CA1031 // Do not catch general exception types
 847                }
 848            }
 849
 850            // ObjectDisposeException can happen
 851            // if the channel is closed in a different
 852            // thread. 99% this check will avoid false
 853            // exceptions.
 19854            return IsOpen && canSendReply;
 855        }
 856
 857        private EndpointDispatcher GetEndpointDispatcher(Message message, out bool addressMatched)
 858        {
 2518859            return _serviceDispatcher.Endpoints.Lookup(message, out addressMatched);
 860        }
 861
 862        private Task TryAcquireThrottleAsync(RequestContext request, bool acquireInstanceContextThrottle)
 863        {
 2539864            ServiceThrottle throttle = _throttle;
 2539865            if ((throttle != null) && (throttle.IsActive))
 866            {
 0867                return throttle.AcquireInstanceContextAndDynamicAsync(this, acquireInstanceContextThrottle);
 868            }
 869
 2539870            return Task.CompletedTask;
 871        }
 872
 873        private Task TryAcquireCallThrottleAsync(RequestContext request)
 874        {
 2557875            ServiceThrottle throttle = _throttle;
 2557876            if ((throttle != null) && (throttle.IsActive))
 877            {
 0878                return throttle.AcquireCallAsync();
 879            }
 880
 2557881            return Task.CompletedTask;
 882        }
 883
 884        private async Task<bool> TryRetrievingInstanceContextAsync(RequestContext request, RequestInfo requestInfo)
 885        {
 886            try
 887            {
 2557888                return await TryRetrievingInstanceContextCoreAsync(request, requestInfo);
 889            }
 890            catch (Exception ex)
 891            {
 0892                if (Fx.IsFatal(ex))
 893                {
 0894                    throw;
 895                }
 896
 0897                DiagnosticUtility.TraceHandledException(ex, TraceEventType.Error);
 898
 899                try
 900                {
 0901                    await request.CloseAsync();
 0902                }
 903                catch (Exception e)
 904                {
 0905                    if (Fx.IsFatal(e))
 906                    {
 0907                        throw;
 908                    }
 909
 0910                    request.Abort();
 0911                }
 912
 0913                return false;
 914            }
 2557915        }
 916
 917        //Return: False denotes failure, Caller should discard the request.
 918        //      : True denotes operation is sucessful.
 919        private async Task<bool> TryRetrievingInstanceContextCoreAsync(RequestContext request, RequestInfo requestInfo)
 920        {
 2557921            bool releasePump = true;
 922            try
 923            {
 2557924                if (!requestInfo.EndpointLookupDone)
 925                {
 2557926                    await EnsureChannelAndEndpointAsync(request, requestInfo);
 927                }
 928
 2541929                if (requestInfo.Channel == null)
 930                {
 2931                    return false;
 932                }
 933
 2539934                if (requestInfo.DispatchRuntime != null)
 935                {
 2539936                    IContextChannel transparentProxy = requestInfo.Channel.Proxy as IContextChannel;
 937                    try
 938                    {
 2539939                        requestInfo.ExistingInstanceContext = requestInfo.DispatchRuntime.InstanceContextProvider.GetExi
 2539940                        releasePump = false;
 2539941                    }
 942                    catch (Exception e)
 943                    {
 0944                        if (Fx.IsFatal(e))
 945                        {
 0946                            throw;
 947                        }
 0948                        requestInfo.Channel = null;
 0949                        await HandleErrorAsync(e, request, requestInfo, _channel);
 0950                        return false;
 951                    }
 952                }
 953                else
 954                {
 955                    // This can happen if we are pumping for an async client,
 956                    // and we receive a bogus reply.  In that case, there is no
 957                    // DispatchRuntime, because we are only expecting replies.
 958                    //
 959                    // One possible fix for this would be in DuplexChannelBinder
 960                    // to drop all messages with a RelatesTo that do not match a
 961                    // pending request.
 962                    //
 963                    // However, that would not fix:
 964                    // (a) we could get a valid request message with a
 965                    // RelatesTo that we should try to process.
 966                    // (b) we could get a reply message that does not have
 967                    // a RelatesTo.
 968                    //
 969                    // So we do the null check here.
 970                    //
 971                    // SFx drops a message here
 0972                    await request.CloseAsync();
 0973                    return false;
 974                }
 2539975            }
 16976            catch (Exception e)
 977            {
 16978                if (Fx.IsFatal(e))
 979                {
 0980                    throw;
 981                }
 982
 16983                await HandleErrorAsync(e, request, requestInfo, _channel);
 984
 16985                return false;
 986            }
 987            finally
 988            {
 2557989                if (releasePump)
 990                {
 18991                    ReleasePump();
 992                }
 993            }
 994
 2539995            return true;
 2557996        }
 997
 998        private void ReleasePump()
 999        {
 71941000            if (_isConcurrent)
 1001            {
 70541002                _asyncManualResetEvent.Set();
 1003            }
 71941004        }
 1005
 1006        private async Task TryAcquirePumpAsync()
 1007        {
 26851008            if (_isConcurrent)
 1009            {
 25871010                await _asyncManualResetEvent.WaitAsync();
 25871011                _asyncManualResetEvent.Reset();
 1012            }
 26851013        }
 1014
 891015        TimeSpan IDefaultCommunicationTimeouts.CloseTimeout => _serviceDispatcher.Binding.CloseTimeout;
 01016        TimeSpan IDefaultCommunicationTimeouts.OpenTimeout => _serviceDispatcher.Binding.OpenTimeout;
 01017        TimeSpan IDefaultCommunicationTimeouts.ReceiveTimeout => _serviceDispatcher.Binding.ReceiveTimeout;
 891018        TimeSpan IDefaultCommunicationTimeouts.SendTimeout => _serviceDispatcher.Binding.SendTimeout;
 1019
 1020        // TODO: Revert back to struct or pool objects.
 1021        internal class RequestInfo
 1022        {
 1023            public EndpointDispatcher Endpoint;
 1024            public InstanceContext ExistingInstanceContext;
 1025            public ServiceChannel Channel;
 1026            public bool EndpointLookupDone;
 1027            public DispatchRuntime DispatchRuntime;
 1028            public RequestContext RequestContext;
 1029            public ChannelHandler ChannelHandler;
 1030            public bool ChannelHandlerOwnsCallThrottle; // if true, we are responsible for call throttle
 1031            public bool ChannelHandlerOwnsInstanceContextThrottle; // if true, we are responsible for instance/dynamic t
 1032
 25581033            public RequestInfo(ChannelHandler channelHandler)
 1034            {
 25581035                Endpoint = null;
 25581036                ExistingInstanceContext = null;
 25581037                Channel = null;
 25581038                EndpointLookupDone = false;
 25581039                DispatchRuntime = null;
 25581040                RequestContext = null;
 25581041                ChannelHandler = channelHandler;
 25581042                ChannelHandlerOwnsCallThrottle = false;
 25581043                ChannelHandlerOwnsInstanceContextThrottle = false;
 25581044            }
 1045
 1046            public void Cleanup()
 1047            {
 01048                if (ChannelHandlerOwnsInstanceContextThrottle)
 1049                {
 01050                    ChannelHandler._throttle?.DeactivateInstanceContext();
 01051                    ChannelHandlerOwnsInstanceContextThrottle = false;
 1052                }
 1053
 01054                Endpoint = null;
 01055                ExistingInstanceContext = null;
 01056                Channel = null;
 01057                EndpointLookupDone = false;
 01058                RequestContext = null;
 01059                if (ChannelHandlerOwnsCallThrottle)
 1060                {
 01061                    ChannelHandler._throttle?.DeactivateCall();
 01062                    ChannelHandlerOwnsCallThrottle = false;
 1063                }
 01064            }
 1065        }
 1066    }
 1067}

Methods/Properties

.cctor()
.ctor(CoreWCF.Channels.MessageVersion,CoreWCF.Dispatcher.IChannelBinder,CoreWCF.Dispatcher.ServiceThrottle,CoreWCF.Dispatcher.ServiceDispatcher,System.Boolean,CoreWCF.Channels.ServiceChannel/SessionIdleManager)
GetDispatcher()
OpenAsync()
HasRegisterBeenCalled()
InstanceContext()
InstanceContextServiceThrottle()
IsOpen()
LocalAddress()
CloseBinderAsync()
EnsureReceive()
DispatchAsync(CoreWCF.Channels.Message)
DispatchAsync()
GetSessionOpenNotificationRequestContext()
HandleRequestAsync()
DispatchAndReleasePumpAsync()
HandleReceiveCompleteAsync()
HandleRequestAsReply(CoreWCF.Channels.RequestContext)
EnsureChannelAndEndpointAsync()
GetDatagramChannelAsync()
GetSessionChannelAsync()
InitializeServiceChannelAsync(CoreWCF.Channels.ServiceChannel)
ProvideFault(System.Exception,CoreWCF.Dispatcher.ChannelHandler/RequestInfo,CoreWCF.Dispatcher.ErrorHandlerFaultInfo&)
HandleError(System.Exception)
HandleError(System.Exception,CoreWCF.Dispatcher.ErrorHandlerFaultInfo&)
HandleErrorAsync(System.Exception,CoreWCF.Channels.RequestContext,CoreWCF.Dispatcher.ChannelHandler/RequestInfo,CoreWCF.Channels.ServiceChannel)
ReplyAddressFilterDidNotMatchAsync(CoreWCF.Channels.RequestContext,CoreWCF.Dispatcher.ChannelHandler/RequestInfo)
ReplyContractFilterDidNotMatchAsync(CoreWCF.Channels.RequestContext,CoreWCF.Dispatcher.ChannelHandler/RequestInfo)
ReplyChannelTerminatedAsync(CoreWCF.Channels.RequestContext,CoreWCF.Dispatcher.ChannelHandler/RequestInfo)
ReplyFailureAsync(CoreWCF.Channels.RequestContext,CoreWCF.Dispatcher.ChannelHandler/RequestInfo,CoreWCF.FaultCode,System.String)
ReplyFailureAsync(CoreWCF.Channels.RequestContext,CoreWCF.Dispatcher.ChannelHandler/RequestInfo,CoreWCF.FaultCode,System.String,System.String)
ReplyFailureAsync()
ProvideFaultAndReplyFailureAsync()
PrepareReply(CoreWCF.Channels.RequestContext,CoreWCF.Channels.Message)
GetEndpointDispatcher(CoreWCF.Channels.Message,System.Boolean&)
TryAcquireThrottleAsync(CoreWCF.Channels.RequestContext,System.Boolean)
TryAcquireCallThrottleAsync(CoreWCF.Channels.RequestContext)
TryRetrievingInstanceContextAsync()
TryRetrievingInstanceContextCoreAsync()
ReleasePump()
TryAcquirePumpAsync()
WCF.IDefaultCommunicationTimeouts.get_CloseTimeout()
WCF.IDefaultCommunicationTimeouts.get_OpenTimeout()
WCF.IDefaultCommunicationTimeouts.get_ReceiveTimeout()
WCF.IDefaultCommunicationTimeouts.get_SendTimeout()
.ctor(CoreWCF.Dispatcher.ChannelHandler)
Cleanup()