< Summary - CoreWCF Coverage — PR #1766

Information
Class: CoreWCF.Channels.ServiceChannel
Assembly: CoreWCF.Primitives
File(s): /home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.Primitives/src/CoreWCF/Channels/ServiceChannel.cs
Line coverage
42%
Covered lines: 230
Uncovered lines: 316
Coverable lines: 546
Total lines: 1759
Line coverage: 42.1%
Branch coverage
42%
Covered branches: 130
Total branches: 304
Branch coverage: 42.7%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.ctor(...)83.33%66100%
.ctor(...)75%8893.33%
SetupInnerChannelFaultHandler()100%11100%
CanCastTo(...)0%660%
CompletedIOOperation()100%22100%
EnsureAutoOpenManagers()0%440%
EnsureOpenedAsync()0%220%
GetProperty()50%2275%
PrepareCall(...)66.66%303073.91%
BeginCall(...)100%110%
BeginCall(...)100%110%
BeginCallAsync()0%660%
CallAsync(...)100%11100%
CallAsync()50%6681.81%
EndCall(...)100%110%
DecrementActivityAsync()87.5%8883.33%
AutoCloseAsync()100%1133.33%
FireUnknownMessageReceived(...)0%220%
GetOpenTimeoutException(...)0%440%
HandleReceiveCompleteAsync(...)100%88100%
HandleReply(...)76.92%262654.83%
TerminateIfNecessary(...)50%2250%
ThrowIfFaultUnderstood(...)0%28280%
ThrowIfIdleAborted(...)75%4440%
ThrowIfIsConnectionOpened(...)50%2250%
ThrowIfOpening()50%2266.66%
IncrementActivity()100%11100%
OnInnerChannelFaulted(...)0%660%
AddMessageProperties(...)66.66%121250%
SendAsync(...)100%110%
SendAsync(...)100%110%
RequestAsync(...)100%110%
RequestAsync()100%110%
OnAbort()100%22100%
OnCloseAsync()100%44100%
OnOpenAsync()100%44100%
CleanupChannelCollections()100%66100%
CoreWCF.IDuplexContextChannel.CloseOutputSessionAsync(...)100%110%
GetDuplexSessionOrThrow()0%440%
CoreWCF.IClientChannel.add_UnknownMessageReceived(...)100%110%
CoreWCF.IClientChannel.remove_UnknownMessageReceived(...)100%110%
System.IDisposable.Dispose()100%110%
CoreWCF.Channels.ServiceChannel.ICallOnce.CallAsync(...)100%110%
.ctor(...)100%110%
.cctor()100%110%
CallOnceAsync()0%12120%
SignalNextIfNonNull(...)50%2266.66%
SignalNext()0%880%
SignalWaiter(...)100%110%
.ctor(...)100%110%
CoreWCF.Channels.ServiceChannel.CallOnceManager.IWaiter.Signal()0%220%
WaitAsync()0%440%
CloseWaitHandle()0%220%
.ctor()100%11100%
UseIfNeeded(...)62.5%8890.9%
CancelTimer()100%22100%
CompletedActivity()100%11100%
RegisterChannel(...)100%11100%
GetTimerCallback()100%22100%
TimerCallback(...)100%11100%
TimerCallback()90%101092.3%

File(s)

/home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.Primitives/src/CoreWCF/Channels/ServiceChannel.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.Collections.Generic;
 6using System.Diagnostics;
 7using System.Globalization;
 8using System.Threading;
 9using System.Threading.Tasks;
 10using CoreWCF.Configuration;
 11using CoreWCF.Description;
 12using CoreWCF.Dispatcher;
 13using CoreWCF.Runtime;
 14
 15namespace CoreWCF.Channels
 16{
 17    // This class is sealed because the constructor could call Abort, which is virtual
 18    internal sealed class ServiceChannel : CommunicationObject, IChannel, IClientChannel, IDuplexContextChannel, IOutput
 19    {
 20        private int _activityCount = 0;
 21        private readonly bool _allowOutputBatching = false;
 51622        private bool _autoClose = true;
 23
 24        //CallOnceManager autoDisplayUIManager;
 25        private CallOnceManager _autoOpenManager;
 51626        private readonly bool _closeBinder = true;
 27        private bool _doneReceiving;
 28        private EndpointDispatcher _endpointDispatcher;
 29        private bool _explicitlyOpened;
 30        private ExtensionCollection<IContextChannel> _extensions;
 31        private readonly SessionIdleManager _idleManager;
 32        private EndpointAddress _localAddress;
 33        private readonly bool _openBinder = false;
 34        private TimeSpan _operationTimeout;
 35        private object _proxy;
 36        private ServiceThrottle _serviceThrottle;
 37        private string _terminatingOperationName;
 38        private bool _hasCleanedUpChannelCollections;
 39
 40        //EventTraceActivity eventActivity;
 41        private readonly IDefaultCommunicationTimeouts _timeouts;
 42        private EventHandler<UnknownMessageReceivedEventArgs> _unknownMessageReceived;
 43
 51644        private ServiceChannel(IChannelBinder binder, Binding binding)
 45        {
 51646            MessageVersion = binding.MessageVersion;
 51647            Binder = binder ?? throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(binder));
 51648            IsReplyChannel = Binder.Channel is IReplyChannel;
 49
 51650            IChannel innerChannel = binder.Channel;
 51651            HasSession = (innerChannel is ISessionChannel<IDuplexSession>) ||
 51652                        (innerChannel is ISessionChannel<IInputSession>) ||
 51653                        (innerChannel is ISessionChannel<IOutputSession>);
 54
 51655            IncrementActivity();
 51656            _openBinder = (binder.Channel.State == CommunicationState.Created);
 57
 51658            _operationTimeout = binding.SendTimeout;
 51659            _timeouts = binding;
 51660        }
 61
 62        // Only used by ServiceChannelFactory
 63        //internal ServiceChannel(ServiceChannelFactory factory, IChannelBinder binder)
 64        //    : this(binder, factory.MessageVersion, factory)
 65        //{
 66        //    this.factory = factory;
 67        //    this.clientRuntime = factory.ClientRuntime;
 68
 69        //    this.SetupInnerChannelFaultHandler();
 70
 71        //    DispatchRuntime dispatch = factory.ClientRuntime.DispatchRuntime;
 72        //    if (dispatch != null)
 73        //    {
 74        //        this.autoClose = dispatch.AutomaticInputSessionShutdown;
 75        //    }
 76
 77        //    factory.ChannelCreated(this);
 78        //}
 79
 80        internal ServiceChannel(IChannelBinder binder,
 81                                EndpointDispatcher endpointDispatcher,
 82                                ServiceDispatcher serviceDispatcher,
 83                                SessionIdleManager idleManager)
 51684            : this(binder, serviceDispatcher.Binding)
 85        {
 51686            ChannelDispatcher = serviceDispatcher.ChannelDispatcher;
 51687            _endpointDispatcher = endpointDispatcher ?? throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull
 51688            ClientRuntime = endpointDispatcher.DispatchRuntime.CallbackClientRuntime;
 89
 51690            SetupInnerChannelFaultHandler();
 91
 51692            _autoClose = endpointDispatcher.DispatchRuntime.AutomaticInputSessionShutdown;
 51693            IsPending = true;
 94
 51695            _idleManager = idleManager;
 96
 51697            if (!binder.HasSession)
 98            {
 43399                _closeBinder = false;
 100            }
 101
 516102            if (_idleManager != null)
 103            {
 83104                _idleManager.RegisterChannel(this, out bool didIdleAbort);
 83105                if (didIdleAbort)
 106                {
 0107                    Abort();
 108                }
 109            }
 516110        }
 111
 112        private CallOnceManager AutoOpenManager
 113        {
 114            get
 115            {
 0116                if (!_explicitlyOpened && (_autoOpenManager == null))
 117                {
 0118                    EnsureAutoOpenManagers();
 119                }
 0120                return _autoOpenManager;
 121            }
 122        }
 123
 124        //CallOnceManager AutoDisplayUIManager
 125        //{
 126        //    get
 127        //    {
 128        //        if (!this.explicitlyOpened && (this.autoDisplayUIManager == null))
 129        //        {
 130        //            this.EnsureAutoOpenManagers();
 131        //        }
 132        //        return this.autoDisplayUIManager;
 133        //    }
 134        //}
 135
 136
 137        //internal EventTraceActivity EventActivity
 138        //{
 139        //    get
 140        //    {
 141        //        if (this.eventActivity == null)
 142        //        {
 143        //            //Take the id on the thread so that we know the initiating operation.
 144        //            this.eventActivity = EventTraceActivity.GetFromThreadOrCreate();
 145        //        }
 146        //        return this.eventActivity;
 147        //    }
 148        //}
 149
 0150        internal bool CloseFactory { get; set; }
 151
 152        protected override TimeSpan DefaultCloseTimeout
 153        {
 0154            get { return CloseTimeout; }
 155        }
 156
 157        protected override TimeSpan DefaultOpenTimeout
 158        {
 516159            get { return OpenTimeout; }
 160        }
 161
 162        internal DispatchRuntime DispatchRuntime
 163        {
 164            get
 165            {
 2644166                if (_endpointDispatcher != null)
 167                {
 2644168                    return _endpointDispatcher.DispatchRuntime;
 169                }
 0170                if (ClientRuntime != null)
 171                {
 0172                    return ClientRuntime.DispatchRuntime;
 173                }
 0174                return null;
 175            }
 176        }
 177
 2539178        internal MessageVersion MessageVersion { get; }
 179
 2578180        internal IChannelBinder Binder { get; }
 181
 182        internal TimeSpan CloseTimeout
 183        {
 184            get
 185            {
 186                //if (this.IsClient)
 187                //{
 188                //    return factory.InternalCloseTimeout;
 189                //}
 190                //else
 191                //{
 2473192                return _timeouts.CloseTimeout;
 193                //}
 194            }
 195        }
 196
 1029197        internal ChannelDispatcher ChannelDispatcher { get; }
 198
 199        internal EndpointDispatcher EndpointDispatcher
 200        {
 106201            get { return _endpointDispatcher; }
 202            set
 203            {
 0204                lock (ThisLock)
 205                {
 0206                    _endpointDispatcher = value;
 0207                    ClientRuntime = value.DispatchRuntime.CallbackClientRuntime;
 0208                }
 0209            }
 210        }
 211
 212        //internal ServiceChannelFactory Factory
 213        //{
 214        //    get { return this.factory; }
 215        //}
 216
 217        internal IChannel InnerChannel
 218        {
 1540219            get { return Binder.Channel; }
 220        }
 221
 3565222        internal bool IsPending { get; set; }
 223
 13214224        internal bool HasSession { get; }
 225
 728226        internal bool IsReplyChannel { get; }
 227
 228        public Uri ListenUri
 229        {
 230            get
 231            {
 0232                return Binder.ListenUri;
 233            }
 234        }
 235
 236        public EndpointAddress LocalAddress
 237        {
 238            get
 239            {
 3240                if (_localAddress == null)
 241                {
 3242                    if (_endpointDispatcher != null)
 243                    {
 3244                        _localAddress = _endpointDispatcher.EndpointAddress;
 245                    }
 246                    else
 247                    {
 0248                        _localAddress = Binder.LocalAddress;
 249                    }
 250                }
 3251                return _localAddress;
 252            }
 253        }
 254
 255        internal TimeSpan OpenTimeout
 256        {
 257            get
 258            {
 259                //if (this.IsClient)
 260                //{
 261                //    return factory.InternalOpenTimeout;
 262                //}
 263                //else
 264                //{
 516265                return ChannelDispatcher.InternalOpenTimeout;
 266                //}
 267            }
 268        }
 269
 270        public TimeSpan OperationTimeout
 271        {
 728272            get { return _operationTimeout; }
 273            set
 274            {
 0275                if (value < TimeSpan.Zero)
 276                {
 0277                    string message = SRCommon.SFxTimeoutOutOfRange0;
 0278                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(val
 279                }
 0280                if (TimeoutHelper.IsTooLarge(value))
 281                {
 0282                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(val
 283                }
 284
 285
 0286                _operationTimeout = value;
 0287            }
 288        }
 289
 290        internal object Proxy
 291        {
 292            get
 293            {
 8113294                object proxy = _proxy;
 8113295                if (proxy != null)
 296                {
 8297                    return proxy;
 298                }
 299                else
 300                {
 8105301                    return this;
 302                }
 303            }
 304            set
 305            {
 1306                _proxy = value;
 1307                EventSender = value;   // need to use "proxy" as open/close event source
 1308            }
 309        }
 310
 1114311        internal ClientRuntime ClientRuntime { get; private set; }
 312
 313        public EndpointAddress RemoteAddress
 314        {
 315            get
 316            {
 683317                if (InnerChannel is IOutputChannel outputChannel)
 318                {
 83319                    return outputChannel.RemoteAddress;
 320                }
 321
 600322                if (InnerChannel is IRequestChannel requestChannel)
 323                {
 0324                    return requestChannel.RemoteAddress;
 325                }
 326
 600327                return null;
 328            }
 329        }
 330
 331        private ProxyOperationRuntime UnhandledProxyOperation
 332        {
 0333            get { return ClientRuntime.GetRuntime().UnhandledProxyOperation; }
 334        }
 335
 336        public Uri Via
 337        {
 338            get
 339            {
 0340                if (InnerChannel is IOutputChannel outputChannel)
 341                {
 0342                    return outputChannel.Via;
 343                }
 344
 0345                if (InnerChannel is IRequestChannel requestChannel)
 346                {
 0347                    return requestChannel.Via;
 348                }
 349
 0350                return null;
 351            }
 352        }
 353
 2541354        internal InstanceContext InstanceContext { get; set; }
 355
 0356        internal ServiceThrottle InstanceContextServiceThrottle { get; set; }
 357
 358        internal ServiceThrottle ServiceThrottle
 359        {
 0360            get { return _serviceThrottle; }
 361            set
 362            {
 0363                ThrowIfDisposed();
 0364                _serviceThrottle = value;
 0365            }
 366        }
 367
 368        private void SetupInnerChannelFaultHandler()
 369        {
 370            // need to call this method after this.binder and this.clientRuntime are set to prevent a potential
 371            // NullReferenceException in this method or in the OnInnerChannelFaulted method;
 372            // because this method accesses this.binder and OnInnerChannelFaulted accesses this.clientRuntime.
 516373            Binder.Channel.Faulted += OnInnerChannelFaulted;
 516374        }
 375
 376        //void BindDuplexCallbacks()
 377        //{
 378        //    IDuplexChannel duplexChannel = this.InnerChannel as IDuplexChannel;
 379        //    if ((duplexChannel != null) && (this.factory != null) && (this.instanceContext != null))
 380        //    {
 381        //        if (this.binder is DuplexChannelBinder)
 382        //            ((DuplexChannelBinder)this.binder).EnsurePumping();
 383        //    }
 384        //}
 385
 386        internal bool CanCastTo(Type t)
 387        {
 0388            if (t.IsAssignableFrom(typeof(IClientChannel)))
 389            {
 0390                return true;
 391            }
 392
 0393            if (t.IsAssignableFrom(typeof(IDuplexContextChannel)))
 394            {
 0395                return InnerChannel is IDuplexChannel;
 396            }
 397
 0398            if (t.IsAssignableFrom(typeof(IServiceChannel)))
 399            {
 0400                return true;
 401            }
 402
 0403            return false;
 404        }
 405
 406        internal void CompletedIOOperation()
 407        {
 3056408            if (_idleManager != null)
 409            {
 190410                _idleManager.CompletedActivity();
 411            }
 3056412        }
 413
 414        private void EnsureAutoOpenManagers()
 415        {
 0416            lock (ThisLock)
 417            {
 0418                if (!_explicitlyOpened)
 419                {
 0420                    if (_autoOpenManager == null)
 421                    {
 0422                        _autoOpenManager = new CallOnceManager(this, CallOpenOnce.Instance);
 423                    }
 424                }
 0425            }
 0426        }
 427
 428        private async Task EnsureOpenedAsync(CancellationToken token)
 429        {
 430            ///// TASKS ******
 0431            CallOnceManager manager = AutoOpenManager;
 0432            if (manager != null)
 433            {
 0434                await manager.CallOnceAsync(token);
 435            }
 436
 0437            ThrowIfOpening();
 0438            ThrowIfDisposedOrNotOpen();
 0439        }
 440
 441        public T GetProperty<T>() where T : class
 442        {
 164443            IChannel innerChannel = InnerChannel;
 164444            if (innerChannel != null)
 445            {
 164446                return innerChannel.GetProperty<T>();
 447            }
 448
 0449            return null;
 450        }
 451
 452        private void PrepareCall(ProxyOperationRuntime operation, bool oneway, ref ProxyRpc rpc)
 453        {
 1454            OperationContext context = OperationContext.Current;
 455            // Doing a request reply callback when dispatching in-order deadlocks.
 456            // We never receive the reply until we finish processing the current message.
 1457            if (!oneway)
 458            {
 1459                DispatchRuntime dispatchBehavior = ClientRuntime.DispatchRuntime;
 1460                if ((dispatchBehavior != null) && (dispatchBehavior.ConcurrencyMode == ConcurrencyMode.Single))
 461                {
 0462                    if ((context != null) && (!context.IsUserContext) && (context.InternalServiceChannel == this))
 463                    {
 0464                        if (dispatchBehavior.IsOnServer)
 465                        {
 0466                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.F
 467                        }
 468                        else
 469                        {
 0470                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.F
 471                        }
 472                    }
 473                }
 474            }
 475
 1476            if ((State == CommunicationState.Created) && !operation.IsInitiating)
 477            {
 0478                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format(SR.SFx
 479            }
 480
 1481            if (_terminatingOperationName != null)
 482            {
 0483                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format(SR.SFx
 484            }
 485
 1486            operation.BeforeRequest(ref rpc);
 1487            AddMessageProperties(rpc.Request, context);
 1488            if (!oneway && !ClientRuntime.ManualAddressing && rpc.Request.Version.Addressing != AddressingVersion.None)
 489            {
 1490                RequestReplyCorrelator.PrepareRequest(rpc.Request);
 491
 1492                MessageHeaders headers = rpc.Request.Headers;
 1493                EndpointAddress localAddress = LocalAddress;
 1494                EndpointAddress replyTo = headers.ReplyTo;
 495
 1496                if (replyTo == null)
 497                {
 1498                    headers.ReplyTo = localAddress ?? EndpointAddress.AnonymousAddress;
 499                }
 500            }
 501
 502            //if (TraceUtility.MessageFlowTracingOnly)
 503            //{
 504            //    //always set a new ID if none provided
 505            //    if (Trace.CorrelationManager.ActivityId == Guid.Empty)
 506            //    {
 507            //        rpc.ActivityId = Guid.NewGuid();
 508            //        FxTrace.Trace.SetAndTraceTransfer(rpc.ActivityId, true);
 509            //    }
 510            //}
 511
 512            //if (rpc.Activity != null)
 513            //{
 514            //    TraceUtility.SetActivity(rpc.Request, rpc.Activity);
 515            //    if (TraceUtility.ShouldPropagateActivity)
 516            //    {
 517            //        TraceUtility.AddActivityHeader(rpc.Request);
 518            //    }
 519            //}
 520            //else if (TraceUtility.PropagateUserActivity || TraceUtility.ShouldPropagateActivity)
 521            //{
 522            //    TraceUtility.AddAmbientActivityToMessage(rpc.Request);
 523            //}
 1524            operation.Parent.BeforeSendRequest(ref rpc);
 525
 526            //Attach and transfer Activity
 527            //if (FxTrace.Trace.IsEnd2EndActivityTracingEnabled)
 528            //{
 529            //    TraceClientOperationPrepared(ref rpc);
 530            //}
 531
 532            //TraceUtility.MessageFlowAtMessageSent(rpc.Request, rpc.EventTraceActivity);
 533
 534            //if (MessageLogger.LogMessagesAtServiceLevel)
 535            //{
 536            //    MessageLogger.LogMessage(ref rpc.Request, (oneway ? MessageLoggingSource.ServiceLevelSendDatagram : Me
 537            //}
 1538        }
 539
 540        //private void TraceClientOperationPrepared(ref ProxyRpc rpc)
 541        //{
 542        //    //Retrieve the old id on the RPC and attach the id on the message since we have a message id now.
 543        //    Guid previousId = rpc.EventTraceActivity != null ? rpc.EventTraceActivity.ActivityId : Guid.Empty;
 544        //    EventTraceActivity requestActivity = EventTraceActivityHelper.TryExtractActivity(rpc.Request);
 545        //    if (requestActivity == null)
 546        //    {
 547        //        requestActivity = EventTraceActivity.GetFromThreadOrCreate();
 548        //        EventTraceActivityHelper.TryAttachActivity(rpc.Request, requestActivity);
 549        //    }
 550        //    rpc.EventTraceActivity = requestActivity;
 551
 552        //    if (TD.ClientOperationPreparedIsEnabled())
 553        //    {
 554        //        string remoteAddress = string.Empty;
 555        //        if (this.RemoteAddress != null && this.RemoteAddress.Uri != null)
 556        //        {
 557        //            remoteAddress = this.RemoteAddress.Uri.AbsoluteUri;
 558        //        }
 559        //        TD.ClientOperationPrepared(rpc.EventTraceActivity,
 560        //                                    rpc.Action,
 561        //                                    this.clientRuntime.ContractName,
 562        //                                    remoteAddress,
 563        //                                    previousId);
 564        //    }
 565
 566        //}
 567
 568        internal IAsyncResult BeginCall(string action, bool oneway, ProxyOperationRuntime operation, object[] ins, Async
 569        {
 0570            return BeginCall(action, oneway, operation, ins, _operationTimeout, callback, asyncState);
 571        }
 572
 573        internal IAsyncResult BeginCall(string action, bool oneway, ProxyOperationRuntime operation, object[] ins, TimeS
 574        {
 0575            var helper = new TimeoutHelper(_operationTimeout);
 0576            return BeginCallAsync(action, oneway, operation, ins, helper.GetCancellationToken()).ToApm(callback, asyncSt
 577        }
 578
 579        internal async Task<ProxyRpc> BeginCallAsync(string action, bool oneway, ProxyOperationRuntime operation, object
 580        {
 0581            ThrowIfIdleAborted(operation);
 0582            ThrowIfIsConnectionOpened(operation);
 583
 0584            ProxyRpc rpc = new ProxyRpc(this, operation, action, ins, token);
 585
 0586            PrepareCall(operation, oneway, ref rpc);
 587
 0588            if (!_explicitlyOpened)
 589            {
 0590                await EnsureOpenedAsync(token);
 591            }
 592            else
 593            {
 0594                ThrowIfOpening();
 0595                ThrowIfDisposedOrNotOpen();
 596            }
 597
 598            try
 599            {
 0600                ConcurrencyBehavior.UnlockInstanceBeforeCallout(OperationContext.Current);
 601
 0602                if (oneway)
 603                {
 0604                    await Binder.SendAsync(rpc.Request, rpc.CancellationToken);
 605                }
 606                else
 607                {
 0608                    rpc.Reply = await Binder.RequestAsync(rpc.Request, rpc.CancellationToken);
 609
 0610                    if (rpc.Reply == null)
 611                    {
 0612                        ThrowIfFaulted();
 0613                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(SR.SFxServe
 614                    }
 615                }
 616            }
 617            finally
 618            {
 0619                CompletedIOOperation();
 0620                CallOnceManager.SignalNextIfNonNull(_autoOpenManager);
 0621                await ConcurrencyBehavior.LockInstanceAfterCalloutAsync(OperationContext.Current);
 622            }
 623
 0624            return rpc;
 0625        }
 626
 627
 628        internal Task<object> CallAsync(string action, bool oneway, ProxyOperationRuntime operation, object[] ins, objec
 629        {
 1630            var helper = new TimeoutHelper(_operationTimeout);
 1631            return CallAsync(action, oneway, operation, ins, outs, helper.GetCancellationToken());
 632        }
 633
 634        internal async Task<object> CallAsync(string action, bool oneway, ProxyOperationRuntime operation, object[] ins,
 635        {
 1636            ThrowIfIdleAborted(operation);
 1637            ThrowIfIsConnectionOpened(operation);
 638
 1639            ProxyRpc rpc = new ProxyRpc(this, operation, action, ins, token);
 640
 641            //TraceServiceChannelCallStart(rpc.EventTraceActivity, true);
 642
 643            //using (rpc.Activity = DiagnosticUtility.ShouldUseActivity ? ServiceModelActivity.CreateBoundedActivity() :
 644            //{
 645            //    if (DiagnosticUtility.ShouldUseActivity)
 646            //    {
 647            //        ServiceModelActivity.Start(rpc.Activity, SR.Format(SR.ActivityProcessAction, action), ActivityType
 648            //    }
 649
 1650            PrepareCall(operation, oneway, ref rpc);
 651
 1652            if (!_explicitlyOpened)
 653            {
 0654                await EnsureOpenedAsync(token);
 655            }
 656            else
 657            {
 1658                ThrowIfOpening();
 1659                ThrowIfDisposedOrNotOpen();
 660            }
 661
 662            try
 663            {
 1664                ConcurrencyBehavior.UnlockInstanceBeforeCallout(OperationContext.Current);
 665
 1666                if (oneway)
 667                {
 0668                    await Binder.SendAsync(rpc.Request, rpc.CancellationToken);
 669                }
 670                else
 671                {
 1672                    rpc.Reply = await Binder.RequestAsync(rpc.Request, rpc.CancellationToken);
 673
 1674                    if (rpc.Reply == null)
 675                    {
 0676                        ThrowIfFaulted();
 0677                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(SR.SFxServe
 678                    }
 679                }
 680            }
 681            finally
 682            {
 1683                CompletedIOOperation();
 1684                CallOnceManager.SignalNextIfNonNull(_autoOpenManager);
 1685                await ConcurrencyBehavior.LockInstanceAfterCalloutAsync(OperationContext.Current);
 686            }
 687
 1688            rpc.OutputParameters = outs;
 1689            HandleReply(operation, ref rpc);
 690            //}
 1691            return rpc.ReturnValue;
 1692        }
 693
 694        internal object EndCall(string action, object[] outs, IAsyncResult result)
 695        {
 0696            ProxyRpc rpc = result.ToApmEnd<ProxyRpc>();
 0697            rpc.OutputParameters = outs;
 0698            HandleReply(rpc.Operation, ref rpc);
 0699            return rpc.ReturnValue;
 700        }
 701
 702        internal Task DecrementActivityAsync()
 703        {
 2558704            int updatedActivityCount = Interlocked.Decrement(ref _activityCount);
 705
 2558706            if (!((updatedActivityCount >= 0)))
 707            {
 0708                throw Fx.AssertAndThrowFatal("ServiceChannel.DecrementActivity: (updatedActivityCount >= 0)");
 709            }
 710
 2558711            if (updatedActivityCount == 0 && _autoClose && State == CommunicationState.Opened)
 712            {
 78713                return AutoCloseAsync();
 714            }
 715
 2480716            return Task.CompletedTask;
 717
 718            async Task AutoCloseAsync()
 719            {
 720                try
 721                {
 78722                    var helper = new TimeoutHelper(CloseTimeout);
 78723                    await CloseAsync(helper.GetCancellationToken());
 78724                }
 725                catch (CommunicationException e)
 726                {
 0727                    DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
 0728                }
 729                catch (TimeoutException e)
 730                {
 731                    //if (TD.CloseTimeoutIsEnabled())
 732                    //{
 733                    //    TD.CloseTimeout(e.Message);
 734                    //}
 0735                    DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
 0736                }
 737                catch (ObjectDisposedException e)
 738                {
 0739                    DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
 0740                }
 741                catch (InvalidOperationException e)
 742                {
 0743                    DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
 0744                }
 78745            }
 746        }
 747
 748        internal void FireUnknownMessageReceived(Message message)
 749        {
 0750            EventHandler<UnknownMessageReceivedEventArgs> handler = _unknownMessageReceived;
 0751            if (handler != null)
 752            {
 0753                handler(_proxy, new UnknownMessageReceivedEventArgs(message));
 754            }
 0755        }
 756
 757        private TimeoutException GetOpenTimeoutException(TimeSpan timeout)
 758        {
 0759            EndpointAddress address = RemoteAddress ?? LocalAddress;
 0760            if (address != null)
 761            {
 0762                return new TimeoutException(SR.Format(SR.TimeoutServiceChannelConcurrentOpen2, address, timeout));
 763            }
 764            else
 765            {
 0766                return new TimeoutException(SR.Format(SR.TimeoutServiceChannelConcurrentOpen1, timeout));
 767            }
 768        }
 769
 770        internal Task HandleReceiveCompleteAsync(RequestContext context)
 771        {
 102772            if (context == null && HasSession)
 773            {
 774                bool first;
 78775                lock (ThisLock)
 776                {
 78777                    first = !_doneReceiving;
 78778                    _doneReceiving = true;
 78779                }
 780
 78781                if (first)
 782                {
 78783                    DispatchRuntime dispatchBehavior = ClientRuntime.DispatchRuntime;
 78784                    if (dispatchBehavior != null)
 785                    {
 78786                        dispatchBehavior.GetRuntime().InputSessionDoneReceiving(this);
 787                    }
 788
 78789                    return DecrementActivityAsync();
 790                }
 791            }
 792
 24793            return Task.CompletedTask;
 794        }
 795
 796        private void HandleReply(ProxyOperationRuntime operation, ref ProxyRpc rpc)
 797        {
 798            try
 799            {
 800                //set the ID after response
 801                //if (TraceUtility.MessageFlowTracingOnly && rpc.ActivityId != Guid.Empty)
 802                //{
 803                //    System.Runtime.Diagnostics.DiagnosticTraceBase.ActivityId = rpc.ActivityId;
 804                //}
 805
 1806                if (rpc.Reply != null)
 807                {
 808                    //TraceUtility.MessageFlowAtMessageReceived(rpc.Reply, null, rpc.EventTraceActivity, false);
 809
 810                    //if (MessageLogger.LogMessagesAtServiceLevel)
 811                    //{
 812                    //    MessageLogger.LogMessage(ref rpc.Reply, MessageLoggingSource.ServiceLevelReceiveReply | Messag
 813                    //}
 1814                    operation.Parent.AfterReceiveReply(ref rpc);
 815
 1816                    if ((operation.ReplyAction != MessageHeaders.WildcardAction) && !rpc.Reply.IsFault && rpc.Reply.Head
 817                    {
 1818                        if (string.CompareOrdinal(operation.ReplyAction, rpc.Reply.Headers.Action) != 0)
 819                        {
 0820                            Exception error = new ProtocolException(SR.Format(SR.SFxReplyActionMismatch3, operation.Name
 0821                                                                                  rpc.Reply.Headers.Action,
 0822                                                                                  operation.ReplyAction));
 0823                            TerminateIfNecessary(ref rpc);
 0824                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(error);
 825                        }
 826                    }
 1827                    if (operation.DeserializeReply && ClientRuntime.IsFault(ref rpc.Reply))
 828                    {
 0829                        MessageFault fault = MessageFault.CreateFault(rpc.Reply, ClientRuntime.MaxFaultSize);
 0830                        string action = rpc.Reply.Headers.Action;
 0831                        if (action == rpc.Reply.Version.Addressing.DefaultFaultAction)
 832                        {
 0833                            action = null;
 834                        }
 0835                        ThrowIfFaultUnderstood(rpc.Reply, fault, action, rpc.Reply.Version, rpc.Channel.GetProperty<Faul
 0836                        FaultException fe = rpc.Operation.FaultFormatter.Deserialize(fault, action);
 0837                        TerminateIfNecessary(ref rpc);
 0838                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(fe);
 839                    }
 840
 1841                    operation.AfterReply(ref rpc);
 842                }
 1843            }
 844            finally
 845            {
 1846                if (operation.SerializeRequest)
 847                {
 1848                    rpc.Request.Close();
 849                }
 850
 1851                OperationContext operationContext = OperationContext.Current;
 1852                bool consumed = ((rpc.Reply != null) && (rpc.Reply.State != MessageState.Created));
 853
 1854                if ((operationContext != null) && operationContext.IsUserContext)
 855                {
 0856                    operationContext.SetClientReply(rpc.Reply, consumed);
 857                }
 1858                else if (consumed)
 859                {
 1860                    rpc.Reply.Close();
 861                }
 862
 863                //if (TraceUtility.MessageFlowTracingOnly)
 864                //{
 865                //    if (rpc.ActivityId != Guid.Empty)
 866                //    {
 867                //        //reset the ID as it was created internally - ensures each call is uniquely correlatable
 868                //        System.Runtime.Diagnostics.DiagnosticTraceBase.ActivityId = Guid.Empty;
 869                //        rpc.ActivityId = Guid.Empty;
 870                //    }
 871                //}
 1872            }
 1873            TerminateIfNecessary(ref rpc);
 874
 875            //if (TD.ServiceChannelCallStopIsEnabled())
 876            //{
 877            //    string remoteAddress = string.Empty;
 878            //    if (this.RemoteAddress != null && this.RemoteAddress.Uri != null)
 879            //    {
 880            //        remoteAddress = this.RemoteAddress.Uri.AbsoluteUri;
 881            //    }
 882            //    TD.ServiceChannelCallStop(rpc.EventTraceActivity, rpc.Action,
 883            //                                this.clientRuntime.ContractName,
 884            //                                remoteAddress);
 885            //}
 1886        }
 887
 888        private void TerminateIfNecessary(ref ProxyRpc rpc)
 889        {
 1890            if (rpc.Operation.IsTerminating)
 891            {
 0892                _terminatingOperationName = rpc.Operation.Name;
 0893                TerminatingOperationBehavior.AfterReply(ref rpc);
 894            }
 1895        }
 896
 897        private void ThrowIfFaultUnderstood(Message reply, MessageFault fault, string action, MessageVersion version, Fa
 898        {
 0899            if (faultConverter != null && faultConverter.TryCreateException(reply, fault, out Exception exception))
 900            {
 0901                throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(exception);
 902            }
 903
 904            bool checkSender;
 905            bool checkReceiver;
 906            FaultCode code;
 907
 0908            if (version.Envelope == EnvelopeVersion.Soap11)
 909            {
 0910                checkSender = true;
 0911                checkReceiver = true;
 0912                code = fault.Code;
 913            }
 914            else
 915            {
 0916                checkSender = fault.Code.IsSenderFault;
 0917                checkReceiver = fault.Code.IsReceiverFault;
 0918                code = fault.Code.SubCode;
 919            }
 920
 0921            if (code == null)
 922            {
 0923                return;
 924            }
 925
 0926            if (code.Namespace == null)
 927            {
 0928                return;
 929            }
 930
 0931            if (checkSender)
 932            {
 0933                if (string.Compare(code.Namespace, FaultCodeConstants.Namespaces.NetDispatch, StringComparison.Ordinal) 
 934                {
 0935                    if (string.Compare(code.Name, FaultCodeConstants.Codes.SessionTerminated, StringComparison.Ordinal) 
 936                    {
 0937                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new ChannelTerminatedException(fault
 938                    }
 939
 940                    //if (string.Compare(code.Name, FaultCodeConstants.Codes.TransactionAborted, StringComparison.Ordina
 941                    //{
 942                    //    throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new ProtocolException(fault.Reason
 943                    //}
 944                }
 945
 946                // throw SecurityAccessDeniedException explicitly
 947                // MessageSecurity
 948                //if (string.Compare(code.Namespace, SecurityVersion.Default.HeaderNamespace.Value, StringComparison.Ord
 949                //{
 950                //    if (string.Compare(code.Name, SecurityVersion.Default.FailedAuthenticationFaultCode.Value, StringC
 951                //    {
 952                //        throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new SecurityAccessDeniedException(
 953                //    }
 954                //}
 955            }
 956
 0957            if (checkReceiver)
 958            {
 0959                if (string.Compare(code.Namespace, FaultCodeConstants.Namespaces.NetDispatch, StringComparison.Ordinal) 
 960                {
 0961                    if (string.Compare(code.Name, FaultCodeConstants.Codes.InternalServiceFault, StringComparison.Ordina
 962                    {
 0963                        if (HasSession)
 964                        {
 0965                            Fault();
 966                        }
 0967                        if (fault.HasDetail)
 968                        {
 0969                            ExceptionDetail detail = fault.GetDetail<ExceptionDetail>();
 0970                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new FaultException<ExceptionDeta
 971                        }
 0972                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new FaultException(fault, action));
 973                    }
 0974                    if (string.Compare(code.Name, FaultCodeConstants.Codes.DeserializationFailed, StringComparison.Ordin
 975                    {
 0976                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new ProtocolException(
 0977                            fault.Reason.GetMatchingTranslation(CultureInfo.CurrentCulture).Text));
 978                    }
 979                }
 980            }
 0981        }
 982
 983        private void ThrowIfIdleAborted(ProxyOperationRuntime operation)
 984        {
 1985            if (_idleManager != null && _idleManager.DidIdleAbort)
 986            {
 0987                string text = SR.Format(SR.SFxServiceChannelIdleAborted, operation.Name);
 0988                Exception error = new CommunicationObjectAbortedException(text);
 0989                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(error);
 990            }
 1991        }
 992
 993        private void ThrowIfIsConnectionOpened(ProxyOperationRuntime operation)
 994        {
 1995            if (operation.IsSessionOpenNotificationEnabled)
 996            {
 0997                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
 0998                    SR.Format(SR.SFxServiceChannelCannotBeCalledBecauseIsSessionOpenNotificationEnabled, operation.Name,
 999            }
 11000        }
 1001
 1002        private void ThrowIfOpening()
 1003        {
 11004            if (State == CommunicationState.Opening)
 1005            {
 01006                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.SFxCannotCall
 1007            }
 11008        }
 1009
 1010        internal void IncrementActivity()
 1011        {
 29961012            Interlocked.Increment(ref _activityCount);
 29961013        }
 1014
 1015        private void OnInnerChannelFaulted(object sender, EventArgs e)
 1016        {
 01017            Fault();
 1018
 01019            if (HasSession)
 1020            {
 01021                DispatchRuntime dispatchRuntime = ClientRuntime.DispatchRuntime;
 01022                if (dispatchRuntime != null)
 1023                {
 01024                    dispatchRuntime.GetRuntime().InputSessionFaulted(this);
 1025                }
 1026            }
 1027
 01028            if (_autoClose)
 1029            {
 01030                Abort();
 1031            }
 01032        }
 1033
 1034        private void AddMessageProperties(Message message, OperationContext context)
 1035        {
 11036            if (_allowOutputBatching)
 1037            {
 01038                message.Properties.AllowOutputBatching = true;
 1039            }
 1040
 11041            if (context != null && context.InternalServiceChannel == this)
 1042            {
 11043                if (!context.OutgoingMessageVersion.IsMatch(message.Headers.MessageVersion))
 1044                {
 01045                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
 01046                        SR.Format(SR.SFxVersionMismatchInOperationContextAndMessage2, context.OutgoingMessageVersion, me
 01047                        ));
 1048                }
 1049
 11050                if (context.HasOutgoingMessageHeaders)
 1051                {
 01052                    message.Headers.CopyHeadersFrom(context.OutgoingMessageHeaders);
 1053                }
 1054
 11055                if (context.HasOutgoingMessageProperties)
 1056                {
 01057                    message.Properties.CopyProperties(context.OutgoingMessageProperties);
 1058                }
 1059            }
 11060        }
 1061
 1062        #region IChannel Members
 1063        public Task SendAsync(Message message)
 1064        {
 01065            var helper = new TimeoutHelper(OperationTimeout);
 01066            return SendAsync(message, helper.GetCancellationToken());
 1067        }
 1068
 1069        public Task SendAsync(Message message, CancellationToken token)
 1070        {
 01071            ProxyOperationRuntime operation = UnhandledProxyOperation;
 01072            return CallAsync(message.Headers.Action, true, operation, new object[] { message }, Array.Empty<object>(), t
 1073        }
 1074
 1075        public Task<Message> RequestAsync(Message message)
 1076        {
 01077            var helper = new TimeoutHelper(OperationTimeout);
 01078            return RequestAsync(message, helper.GetCancellationToken());
 1079        }
 1080
 1081        public async Task<Message> RequestAsync(Message message, CancellationToken token)
 1082        {
 01083            ProxyOperationRuntime operation = UnhandledProxyOperation;
 01084            return (Message)await CallAsync(message.Headers.Action, false, operation, new object[] { message }, Array.Em
 01085        }
 1086
 1087        protected override void OnAbort()
 1088        {
 11089            if (_idleManager != null)
 1090            {
 11091                _idleManager.CancelTimer();
 1092            }
 1093
 11094            Binder.Abort();
 1095
 11096            CleanupChannelCollections();
 1097
 1098            //ServiceThrottle serviceThrottle = this.serviceThrottle;
 1099            //if (serviceThrottle != null)
 1100            //    serviceThrottle.DeactivateChannel();
 1101
 1102            //rollback the attached transaction if one is present
 1103            //if ((this.instanceContext != null) && this.HasSession)
 1104            //{
 1105            //    if (instanceContext.HasTransaction)
 1106            //    {
 1107            //        instanceContext.Transaction.CompletePendingTransaction(instanceContext.Transaction.Attached, new E
 1108            //    }
 1109            //}
 11110        }
 1111
 1112        protected override async Task OnCloseAsync(CancellationToken token)
 1113        {
 781114            if (_idleManager != null)
 1115            {
 781116                _idleManager.CancelTimer();
 1117            }
 1118
 1119            //if (this.InstanceContext != null && this.InstanceContext.HasTransaction)
 1120            //{
 1121            //    this.InstanceContext.CompleteAttachedTransaction();
 1122            //}
 1123
 781124            if (_closeBinder)
 1125            {
 781126                await InnerChannel.CloseAsync(token);
 1127            }
 1128
 781129            CleanupChannelCollections();
 1130
 1131            //ServiceThrottle serviceThrottle = this.serviceThrottle;
 1132            //if (serviceThrottle != null)
 1133            //{
 1134            //    serviceThrottle.DeactivateChannel();
 1135            //}
 781136        }
 1137
 1138        protected override async Task OnOpenAsync(CancellationToken token)
 1139        {
 5161140            if (_autoOpenManager == null)
 1141            {
 5161142                _explicitlyOpened = true;
 1143            }
 1144
 1145            //this.TraceChannelOpenStarted();
 1146
 5161147            if (_openBinder)
 1148            {
 151149                await InnerChannel.OpenAsync(token);
 1150            }
 1151
 5161152            CompletedIOOperation();
 1153
 1154            //this.TraceChannelOpenCompleted();
 5161155        }
 1156
 1157        private void CleanupChannelCollections()
 1158        {
 791159            if (!_hasCleanedUpChannelCollections)
 1160            {
 791161                lock (ThisLock)
 1162                {
 791163                    if (!_hasCleanedUpChannelCollections)
 1164                    {
 791165                        if (InstanceContext != null)
 1166                        {
 791167                            InstanceContext.OutgoingChannels.Remove((IChannel)_proxy);
 1168                        }
 1169
 791170                        _hasCleanedUpChannelCollections = true;
 1171                    }
 791172                }
 1173            }
 791174        }
 1175        #endregion
 1176
 1177        #region IClientChannel Members
 1178
 1179        bool IDuplexContextChannel.AutomaticInputSessionShutdown
 1180        {
 01181            get { return _autoClose; }
 01182            set { _autoClose = value; }
 1183        }
 1184
 1185        //bool IContextChannel.AllowOutputBatching
 1186        //{
 1187        //    get { return this.allowOutputBatching; }
 1188        //    set { this.allowOutputBatching = value; }
 1189        //}
 1190
 1191        Task IDuplexContextChannel.CloseOutputSessionAsync(CancellationToken token)
 1192        {
 01193            return GetDuplexSessionOrThrow().CloseOutputSessionAsync(token);
 1194        }
 1195
 1196        private IDuplexSession GetDuplexSessionOrThrow()
 1197        {
 01198            if (InnerChannel == null)
 1199            {
 01200                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.channelIsNotA
 1201            }
 1202
 01203            if (!(InnerChannel is ISessionChannel<IDuplexSession> duplexSessionChannel))
 1204            {
 01205                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.channelDoesNo
 1206            }
 1207
 01208            return duplexSessionChannel.Session;
 1209        }
 1210
 1211        IExtensionCollection<IContextChannel> IExtensibleObject<IContextChannel>.Extensions
 1212        {
 1213            get
 1214            {
 01215                lock (ThisLock)
 1216                {
 01217                    if (_extensions == null)
 1218                    {
 01219                        _extensions = new ExtensionCollection<IContextChannel>((IContextChannel)Proxy, ThisLock);
 1220                    }
 1221
 01222                    return _extensions;
 1223                }
 01224            }
 1225        }
 1226
 1227        InstanceContext IDuplexContextChannel.CallbackInstance
 1228        {
 01229            get { return InstanceContext; }
 1230            set
 1231            {
 01232                lock (ThisLock)
 1233                {
 01234                    if (InstanceContext != null)
 1235                    {
 01236                        InstanceContext.OutgoingChannels.Remove((IChannel)_proxy);
 1237                    }
 1238
 01239                    InstanceContext = value;
 1240
 01241                    if (InstanceContext != null)
 1242                    {
 01243                        InstanceContext.OutgoingChannels.Add((IChannel)_proxy);
 1244                    }
 01245                }
 01246            }
 1247        }
 1248
 1249        IInputSession IContextChannel.InputSession
 1250        {
 1251            get
 1252            {
 01253                if (InnerChannel != null)
 1254                {
 01255                    if (InnerChannel is ISessionChannel<IInputSession> inputSession)
 1256                    {
 01257                        return inputSession.Session;
 1258                    }
 1259
 01260                    if (InnerChannel is ISessionChannel<IDuplexSession> duplexSession)
 1261                    {
 01262                        return duplexSession.Session;
 1263                    }
 1264                }
 1265
 01266                return null;
 1267            }
 1268        }
 1269
 1270        IOutputSession IContextChannel.OutputSession
 1271        {
 1272            get
 1273            {
 01274                if (InnerChannel != null)
 1275                {
 01276                    if (InnerChannel is ISessionChannel<IOutputSession> outputSession)
 1277                    {
 01278                        return outputSession.Session;
 1279                    }
 1280
 01281                    if (InnerChannel is ISessionChannel<IDuplexSession> duplexSession)
 1282                    {
 01283                        return duplexSession.Session;
 1284                    }
 1285                }
 1286
 01287                return null;
 1288            }
 1289        }
 1290
 1291        string IContextChannel.SessionId
 1292        {
 1293            get
 1294            {
 01295                if (InnerChannel != null)
 1296                {
 01297                    if (InnerChannel is ISessionChannel<IInputSession> inputSession)
 1298                    {
 01299                        return inputSession.Session.Id;
 1300                    }
 1301
 01302                    if (InnerChannel is ISessionChannel<IOutputSession> outputSession)
 1303                    {
 01304                        return outputSession.Session.Id;
 1305                    }
 1306
 01307                    if (InnerChannel is ISessionChannel<IDuplexSession> duplexSession)
 1308                    {
 01309                        return duplexSession.Session.Id;
 1310                    }
 1311                }
 1312
 01313                return null;
 1314            }
 1315        }
 1316
 1317        IServiceChannelDispatcher IChannel.ChannelDispatcher
 1318        {
 01319            get => throw new NotSupportedException();
 01320            set => throw new NotSupportedException();
 1321        }
 1322
 1323        event EventHandler<UnknownMessageReceivedEventArgs> IClientChannel.UnknownMessageReceived
 1324        {
 1325            add
 1326            {
 01327                lock (ThisLock)
 1328                {
 01329                    _unknownMessageReceived += value;
 01330                }
 01331            }
 1332            remove
 1333            {
 01334                lock (ThisLock)
 1335                {
 01336                    _unknownMessageReceived -= value;
 01337                }
 01338            }
 1339        }
 1340
 1341        void IDisposable.Dispose()
 1342        {
 01343            CloseAsync().GetAwaiter().GetResult();
 01344        }
 1345
 1346        #endregion
 1347
 1348        //void TraceChannelOpenStarted()
 1349        //{
 1350        //    if (TD.ClientChannelOpenStartIsEnabled() && this.endpointDispatcher == null)
 1351        //    {
 1352        //        TD.ClientChannelOpenStart(this.EventActivity);
 1353        //    }
 1354        //    else if (TD.ServiceChannelOpenStartIsEnabled())
 1355        //    {
 1356        //        TD.ServiceChannelOpenStart(this.EventActivity);
 1357        //    }
 1358
 1359        //    //if (DiagnosticUtility.ShouldTraceInformation)
 1360        //    //{
 1361        //    //    Dictionary<string, string> values = new Dictionary<string, string>(4);
 1362        //    //    bool traceNeeded = false;
 1363        //    //    DispatchRuntime behavior = this.DispatchRuntime;
 1364        //    //    if (behavior != null)
 1365        //    //    {
 1366        //    //        if (behavior.Type != null)
 1367        //    //        {
 1368        //    //            values["ServiceType"] = behavior.Type.AssemblyQualifiedName;
 1369        //    //        }
 1370        //    //        values["ContractNamespace"] = this.clientRuntime.ContractNamespace;
 1371        //    //        values["ContractName"] = this.clientRuntime.ContractName;
 1372        //    //        traceNeeded = true;
 1373        //    //    }
 1374        //    //    if ((this.endpointDispatcher != null) && (this.endpointDispatcher.ListenUri != null))
 1375        //    //    {
 1376        //    //        values["Uri"] = this.endpointDispatcher.ListenUri.ToString();
 1377        //    //        traceNeeded = true;
 1378        //    //    }
 1379        //    //    if (traceNeeded)
 1380        //    //    {
 1381        //    //        TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.ServiceChannelLifetime,
 1382        //    //            SR.Format(SR.TraceCodeServiceChannelLifetime),
 1383        //    //            new DictionaryTraceRecord(values), this, null);
 1384        //    //    }
 1385        //    //}
 1386        //}
 1387
 1388        //void TraceChannelOpenCompleted()
 1389        //{
 1390        //    if (this.endpointDispatcher == null && TD.ClientChannelOpenStopIsEnabled())
 1391        //    {
 1392        //        TD.ClientChannelOpenStop(this.EventActivity);
 1393        //    }
 1394        //    else if (TD.ServiceChannelOpenStopIsEnabled())
 1395        //    {
 1396        //        TD.ServiceChannelOpenStop(this.EventActivity);
 1397        //    }
 1398        //}
 1399
 1400        //static void TraceServiceChannelCallStart(EventTraceActivity eventTraceActivity, bool isSynchronous)
 1401        //{
 1402        //    if (TD.ServiceChannelCallStartIsEnabled())
 1403        //    {
 1404        //        if (isSynchronous)
 1405        //        {
 1406        //            TD.ServiceChannelCallStart(eventTraceActivity);
 1407        //        }
 1408        //        else
 1409        //        {
 1410        //            TD.ServiceChannelBeginCallStart(eventTraceActivity);
 1411        //        }
 1412        //    }
 1413        //}
 1414
 1415        // Invariants for signalling the CallOnce manager.
 1416        //
 1417        // 1) If a Call, BeginCall, or EndCall on the channel throws,
 1418        //    the manager will SignalNext itself.
 1419        // 2) If a Waiter times out, it will SignalNext its manager
 1420        //    once it is both timed out and signalled.
 1421        // 3) Once Call or EndCall returns successfully, it guarantees
 1422        //    that SignalNext will be called once the // next stage
 1423        //    has sufficiently completed.
 1424        private interface ICallOnce
 1425        {
 1426            Task CallAsync(ServiceChannel channel, CancellationToken token);
 1427        }
 1428
 1429        private class CallOpenOnce : ICallOnce
 1430        {
 1431            private static CallOpenOnce s_instance;
 1432
 1433            internal static CallOpenOnce Instance
 1434            {
 1435                get
 1436                {
 01437                    if (s_instance == null)
 1438                    {
 01439                        s_instance = new CallOpenOnce();
 1440                    }
 01441                    return s_instance;
 1442                }
 1443            }
 1444
 1445            Task ICallOnce.CallAsync(ServiceChannel channel, CancellationToken token)
 1446            {
 01447                return channel.OpenAsync(token);
 1448            }
 1449        }
 1450
 1451        private class CallOnceManager
 1452        {
 1453            private readonly ICallOnce _callOnce;
 1454            private readonly ServiceChannel _channel;
 01455            private bool _isFirst = true;
 1456            private Queue<IWaiter> _queue;
 01457            private static readonly Action<object> s_signalWaiter = SignalWaiter;
 1458
 01459            internal CallOnceManager(ServiceChannel channel, ICallOnce callOnce)
 1460            {
 01461                _callOnce = callOnce;
 01462                _channel = channel;
 01463                _queue = new Queue<IWaiter>();
 01464            }
 1465
 1466            private object ThisLock
 1467            {
 01468                get { return this; }
 1469            }
 1470
 1471            internal async Task CallOnceAsync(CancellationToken token)
 1472            {
 01473                AsyncWaiter waiter = null;
 01474                bool first = false;
 1475
 01476                if (_queue != null)
 1477                {
 01478                    lock (ThisLock)
 1479                    {
 01480                        if (_queue != null)
 1481                        {
 01482                            if (_isFirst)
 1483                            {
 01484                                first = true;
 01485                                _isFirst = false;
 1486                            }
 1487                            else
 1488                            {
 01489                                waiter = new AsyncWaiter(this);
 01490                                _queue.Enqueue(waiter);
 1491                            }
 1492                        }
 01493                    }
 1494                }
 1495
 01496                if (first)
 1497                {
 01498                    bool throwing = true;
 1499                    try
 1500                    {
 01501                        await _callOnce.CallAsync(_channel, token);
 01502                        throwing = false;
 01503                    }
 1504                    finally
 1505                    {
 01506                        if (throwing)
 1507                        {
 01508                            SignalNext();
 1509                        }
 1510                    }
 1511                }
 01512                else if (waiter != null)
 1513                {
 01514                    await waiter.WaitAsync(token);
 1515                }
 01516            }
 1517
 1518            internal static void SignalNextIfNonNull(CallOnceManager manager)
 1519            {
 11520                if (manager != null)
 1521                {
 01522                    manager.SignalNext();
 1523                }
 11524            }
 1525
 1526            internal void SignalNext()
 1527            {
 01528                if (_queue == null)
 1529                {
 01530                    return;
 1531                }
 1532
 01533                IWaiter waiter = null;
 1534
 01535                lock (ThisLock)
 1536                {
 01537                    if (_queue != null)
 1538                    {
 01539                        if (_queue.Count > 0)
 1540                        {
 01541                            waiter = _queue.Dequeue();
 1542                        }
 1543                        else
 1544                        {
 01545                            _queue = null;
 1546                        }
 1547                    }
 01548                }
 1549
 01550                if (waiter != null)
 1551                {
 01552                    ActionItem.Schedule(s_signalWaiter, waiter);
 1553                }
 01554            }
 1555
 1556            private static void SignalWaiter(object state)
 1557            {
 01558                ((IWaiter)state).Signal();
 01559            }
 1560
 1561            private interface IWaiter
 1562            {
 1563                void Signal();
 1564            }
 1565
 1566            private class AsyncWaiter : IWaiter
 1567            {
 01568                private readonly AsyncManualResetEvent _wait = new AsyncManualResetEvent();
 1569                private readonly CallOnceManager _manager;
 1570                private bool _isTimedOut = false;
 1571                private bool _isSignaled = false;
 1572                private int _waitCount = 0;
 1573
 01574                internal AsyncWaiter(CallOnceManager manager)
 1575                {
 01576                    _manager = manager;
 01577                }
 1578
 1579                private bool ShouldSignalNext
 1580                {
 01581                    get { return _isTimedOut && _isSignaled; }
 1582                }
 1583
 1584                void IWaiter.Signal()
 1585                {
 01586                    _wait.Set();
 01587                    CloseWaitHandle();
 1588
 1589                    bool signalNext;
 01590                    lock (_manager.ThisLock)
 1591                    {
 01592                        _isSignaled = true;
 01593                        signalNext = ShouldSignalNext;
 01594                    }
 01595                    if (signalNext)
 1596                    {
 01597                        _manager.SignalNext();
 1598                    }
 01599                }
 1600
 1601                internal async Task<bool> WaitAsync(CancellationToken token)
 1602                {
 1603                    try
 1604                    {
 01605                        if (!await _wait.WaitAsync(token))
 1606                        {
 1607                            bool signalNext;
 01608                            lock (_manager.ThisLock)
 1609                            {
 01610                                _isTimedOut = true;
 01611                                signalNext = ShouldSignalNext;
 01612                            }
 01613                            if (signalNext)
 1614                            {
 01615                                _manager.SignalNext();
 1616                            }
 1617                        }
 01618                    }
 1619                    finally
 1620                    {
 01621                        CloseWaitHandle();
 1622                    }
 1623
 01624                    return !_isTimedOut;
 01625                }
 1626
 1627                private void CloseWaitHandle()
 1628                {
 01629                    if (Interlocked.Increment(ref _waitCount) == 2)
 1630                    {
 01631                        _wait.Dispose();
 1632                    }
 01633                }
 1634            }
 1635        }
 1636
 1637        internal class SessionIdleManager
 1638        {
 1639            private IChannelBinder _binder;
 1640            private ServiceChannel _channel;
 1641            private long _idleTicks;
 1642            private long _lastActivity;
 1643            private IOThreadTimer _timer;
 1644            private static Action<object> s_timerCallback;
 1645            private bool _didIdleAbort;
 1646            private bool _isTimerCancelled;
 1647            private object _thisLock;
 1648            private bool? _isNeeded = null;
 1649
 22921650            public SessionIdleManager()
 1651            {
 22921652                _thisLock = new object();
 22921653            }
 1654
 1655            internal SessionIdleManager UseIfNeeded(IChannelBinder binder, TimeSpan idle)
 1656            {
 5161657                if (_isNeeded.HasValue)
 1658                {
 01659                    return _isNeeded.Value ? this : null;
 1660                }
 1661
 5161662                if (binder.HasSession && (idle != TimeSpan.MaxValue))
 1663                {
 831664                    _binder = binder;
 831665                    _timer = new IOThreadTimer(GetTimerCallback(), this, false);
 831666                    _idleTicks = Ticks.FromTimeSpan(idle);
 831667                    _timer.SetAt(Ticks.Now + _idleTicks);
 831668                    _isNeeded = true;
 831669                    return this;
 1670                }
 1671                else
 1672                {
 4331673                    _isNeeded = false;
 4331674                    return null;
 1675                }
 1676            }
 1677
 1678            internal bool DidIdleAbort
 1679            {
 1680                get
 1681                {
 11682                    lock (_thisLock)
 1683                    {
 11684                        return _didIdleAbort;
 1685                    }
 11686                }
 1687            }
 1688
 1689            internal void CancelTimer()
 1690            {
 821691                lock (_thisLock)
 1692                {
 821693                    _isTimerCancelled = true;
 821694                    _timer?.Cancel();
 791695                }
 821696            }
 1697
 1698            internal void CompletedActivity()
 1699            {
 1901700                Interlocked.Exchange(ref _lastActivity, Ticks.Now);
 1901701            }
 1702
 1703            internal void RegisterChannel(ServiceChannel channel, out bool didIdleAbort)
 1704            {
 831705                lock (_thisLock)
 1706                {
 831707                    _channel = channel;
 831708                    didIdleAbort = _didIdleAbort;
 831709                }
 831710            }
 1711
 1712            private static Action<object> GetTimerCallback()
 1713            {
 831714                if (s_timerCallback == null)
 1715                {
 41716                    s_timerCallback = TimerCallback;
 1717                }
 831718                return s_timerCallback;
 1719            }
 1720
 1721            private static void TimerCallback(object state)
 1722            {
 21723                ((SessionIdleManager)state).TimerCallback();
 21724            }
 1725
 1726            private void TimerCallback()
 1727            {
 1728                // This reads lastActivity atomically without changing its value.
 1729                // (it only sets if it is zero, and then it sets it to zero).
 21730                long last = Interlocked.CompareExchange(ref _lastActivity, 0, 0);
 21731                long abortTime = last + _idleTicks;
 1732
 21733                lock (_thisLock)
 1734                {
 21735                    long ticksNow = Ticks.Now;
 21736                    if (ticksNow > abortTime)
 1737                    {
 11738                        _didIdleAbort = true;
 11739                        if (_channel != null)
 1740                        {
 11741                            _channel.Abort();
 1742                        }
 1743                        else
 1744                        {
 01745                            _binder.Abort();
 1746                        }
 1747                    }
 1748                    else
 1749                    {
 11750                        if (!_isTimerCancelled && _binder.Channel.State != CommunicationState.Faulted && _binder.Channel
 1751                        {
 11752                            _timer.SetAt(abortTime);
 1753                        }
 1754                    }
 11755                }
 21756            }
 1757        }
 1758    }
 1759}

Methods/Properties

.ctor(CoreWCF.Dispatcher.IChannelBinder,CoreWCF.Channels.Binding)
.ctor(CoreWCF.Dispatcher.IChannelBinder,CoreWCF.Dispatcher.EndpointDispatcher,CoreWCF.Dispatcher.ServiceDispatcher,CoreWCF.Channels.ServiceChannel/SessionIdleManager)
AutoOpenManager()
CloseFactory()
DefaultCloseTimeout()
DefaultOpenTimeout()
DispatchRuntime()
MessageVersion()
Binder()
CloseTimeout()
ChannelDispatcher()
EndpointDispatcher()
EndpointDispatcher(CoreWCF.Dispatcher.EndpointDispatcher)
InnerChannel()
IsPending()
HasSession()
IsReplyChannel()
ListenUri()
LocalAddress()
OpenTimeout()
OperationTimeout()
OperationTimeout(System.TimeSpan)
Proxy()
Proxy(System.Object)
ClientRuntime()
RemoteAddress()
UnhandledProxyOperation()
Via()
InstanceContext()
InstanceContextServiceThrottle()
ServiceThrottle()
ServiceThrottle(CoreWCF.Dispatcher.ServiceThrottle)
SetupInnerChannelFaultHandler()
CanCastTo(System.Type)
CompletedIOOperation()
EnsureAutoOpenManagers()
EnsureOpenedAsync()
GetProperty()
PrepareCall(CoreWCF.Dispatcher.ProxyOperationRuntime,System.Boolean,CoreWCF.Dispatcher.ProxyRpc&)
BeginCall(System.String,System.Boolean,CoreWCF.Dispatcher.ProxyOperationRuntime,System.Object[],System.AsyncCallback,System.Object)
BeginCall(System.String,System.Boolean,CoreWCF.Dispatcher.ProxyOperationRuntime,System.Object[],System.TimeSpan,System.AsyncCallback,System.Object)
BeginCallAsync()
CallAsync(System.String,System.Boolean,CoreWCF.Dispatcher.ProxyOperationRuntime,System.Object[],System.Object[])
CallAsync()
EndCall(System.String,System.Object[],System.IAsyncResult)
DecrementActivityAsync()
AutoCloseAsync()
FireUnknownMessageReceived(CoreWCF.Channels.Message)
GetOpenTimeoutException(System.TimeSpan)
HandleReceiveCompleteAsync(CoreWCF.Channels.RequestContext)
HandleReply(CoreWCF.Dispatcher.ProxyOperationRuntime,CoreWCF.Dispatcher.ProxyRpc&)
TerminateIfNecessary(CoreWCF.Dispatcher.ProxyRpc&)
ThrowIfFaultUnderstood(CoreWCF.Channels.Message,CoreWCF.Channels.MessageFault,System.String,CoreWCF.Channels.MessageVersion,CoreWCF.Channels.FaultConverter)
ThrowIfIdleAborted(CoreWCF.Dispatcher.ProxyOperationRuntime)
ThrowIfIsConnectionOpened(CoreWCF.Dispatcher.ProxyOperationRuntime)
ThrowIfOpening()
IncrementActivity()
OnInnerChannelFaulted(System.Object,System.EventArgs)
AddMessageProperties(CoreWCF.Channels.Message,CoreWCF.OperationContext)
SendAsync(CoreWCF.Channels.Message)
SendAsync(CoreWCF.Channels.Message,System.Threading.CancellationToken)
RequestAsync(CoreWCF.Channels.Message)
RequestAsync()
OnAbort()
OnCloseAsync()
OnOpenAsync()
CleanupChannelCollections()
WCF.IDuplexContextChannel.get_AutomaticInputSessionShutdown()
WCF.IDuplexContextChannel.set_AutomaticInputSessionShutdown(System.Boolean)
CoreWCF.IDuplexContextChannel.CloseOutputSessionAsync(System.Threading.CancellationToken)
GetDuplexSessionOrThrow()
WCF.IExtensibleObject<CoreWCF.IContextChannel>.get_Extensions()
WCF.IDuplexContextChannel.get_CallbackInstance()
WCF.IDuplexContextChannel.set_CallbackInstance(CoreWCF.InstanceContext)
WCF.IContextChannel.get_InputSession()
WCF.IContextChannel.get_OutputSession()
WCF.IContextChannel.get_SessionId()
WCF.Channels.IChannel.get_ChannelDispatcher()
WCF.Channels.IChannel.set_ChannelDispatcher(CoreWCF.Configuration.IServiceChannelDispatcher)
CoreWCF.IClientChannel.add_UnknownMessageReceived(System.EventHandler`1<CoreWCF.UnknownMessageReceivedEventArgs>)
CoreWCF.IClientChannel.remove_UnknownMessageReceived(System.EventHandler`1<CoreWCF.UnknownMessageReceivedEventArgs>)
System.IDisposable.Dispose()
Instance()
CoreWCF.Channels.ServiceChannel.ICallOnce.CallAsync(CoreWCF.Channels.ServiceChannel,System.Threading.CancellationToken)
.ctor(CoreWCF.Channels.ServiceChannel,CoreWCF.Channels.ServiceChannel/ICallOnce)
.cctor()
ThisLock()
CallOnceAsync()
SignalNextIfNonNull(CoreWCF.Channels.ServiceChannel/CallOnceManager)
SignalNext()
SignalWaiter(System.Object)
.ctor(CoreWCF.Channels.ServiceChannel/CallOnceManager)
ShouldSignalNext()
CoreWCF.Channels.ServiceChannel.CallOnceManager.IWaiter.Signal()
WaitAsync()
CloseWaitHandle()
.ctor()
UseIfNeeded(CoreWCF.Dispatcher.IChannelBinder,System.TimeSpan)
DidIdleAbort()
CancelTimer()
CompletedActivity()
RegisterChannel(CoreWCF.Channels.ServiceChannel,System.Boolean&)
GetTimerCallback()
TimerCallback(System.Object)
TimerCallback()