< Summary - CoreWCF Coverage — PR #1766

Information
Class: CoreWCF.InstanceContext
Assembly: CoreWCF.Primitives
File(s): /home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.Primitives/src/CoreWCF/InstanceContext.cs
Line coverage
70%
Covered lines: 126
Uncovered lines: 52
Coverable lines: 178
Total lines: 486
Line coverage: 70.7%
Branch coverage
75%
Covered branches: 56
Total branches: 74
Branch coverage: 75.6%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.cctor()100%11100%
.ctor(...)100%22100%
.ctor(...)100%110%
.ctor(...)100%110%
.ctor(...)100%11100%
.ctor(...)50%22100%
OnAbort()100%11100%
CloseInputAsync(...)100%110%
BindRpc(...)100%11100%
BindIncomingChannel(...)62.5%8890.9%
CloseIfNotBusy()70%101042.1%
EnsureQuotaThrottle()0%220%
FaultInternal()100%110%
GetServiceInstance()100%11100%
GetServiceInstance(...)60%101070.58%
Load()100%44100%
NotifyEmpty(...)100%22100%
NotifyIdle(...)100%110%
OnCloseAsync()100%11100%
OnClosed()50%2266.66%
OnFaulted()0%220%
OnOpenAsync(...)100%11100%
OnOpened()100%11100%
OnOpening()100%11100%
ReleaseServiceInstance()100%110%
SetUserObject(...)100%1010100%
UnbindRpc(...)100%44100%
Unload()100%22100%

File(s)

/home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.Primitives/src/CoreWCF/InstanceContext.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.Threading;
 8using System.Threading.Tasks;
 9using CoreWCF.Channels;
 10using CoreWCF.Diagnostics;
 11using CoreWCF.Dispatcher;
 12using CoreWCF.Runtime;
 13
 14namespace CoreWCF
 15{
 16    public sealed class InstanceContext : CommunicationObject, IExtensibleObject<InstanceContext>
 17    {
 718        internal static Action<InstanceContext> NotifyEmptyCallback = NotifyEmpty;
 719        internal static Action<InstanceContext> NotifyIdleCallback = NotifyIdle;
 20        private InstanceBehavior _behavior;
 21        private readonly ServiceChannelManager _channels;
 22        private ConcurrencyInstanceContextFacet _concurrency;
 23        private ExtensionCollection<InstanceContext> _extensions;
 24        private readonly ServiceHostBase _host;
 25        private ServiceThrottle _serviceThrottle;
 249326        private readonly object _serviceInstanceLock = new object();
 27        private SynchronizationContext _synchronizationContext;
 28        private object _userObject;
 29
 30        public InstanceContext(object implementation)
 031            : this(null, implementation)
 32        {
 033        }
 34
 35        public InstanceContext(ServiceHostBase host, object implementation)
 036            : this(host, implementation, true)
 37        {
 038        }
 39
 40        internal InstanceContext(ServiceHostBase host, object implementation, bool isUserCreated)
 2341            : this(host, implementation, true, isUserCreated)
 42        {
 2343        }
 44
 10245        internal InstanceContext(ServiceHostBase host, object implementation, bool wellKnown, bool isUserCreated)
 46        {
 10247            _host = host;
 10248            if (implementation != null)
 49            {
 10250                _userObject = implementation;
 10251                IsWellKnown = wellKnown;
 52            }
 10253            AutoClose = false;
 10254            _channels = new ServiceChannelManager(this);
 10255            IsUserCreated = isUserCreated;
 10256        }
 57
 239158        internal InstanceContext(ServiceHostBase host, bool isUserCreated)
 59        {
 239160            _host = host ?? throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(host));
 239161            AutoClose = true;
 239162            _channels = new ServiceChannelManager(this, NotifyEmptyCallback);
 239163            IsUserCreated = isUserCreated;
 239164        }
 65
 257566        internal bool IsUserCreated { get; set; }
 67
 480368        internal bool IsWellKnown { get; }
 69
 490470        internal bool AutoClose { get; set; }
 71
 72        internal InstanceBehavior Behavior
 73        {
 074            get { return _behavior; }
 75            set
 76            {
 266177                if (_behavior == null)
 78                {
 249379                    _behavior = value;
 80                }
 266181            }
 82        }
 83
 84        internal ConcurrencyInstanceContextFacet Concurrency
 85        {
 86            get
 87            {
 465488                if (_concurrency == null)
 89                {
 230090                    lock (ThisLock)
 91                    {
 230092                        if (_concurrency == null)
 93                        {
 230094                            _concurrency = new ConcurrencyInstanceContextFacet();
 95                        }
 230096                    }
 97                }
 98
 465499                return _concurrency;
 100            }
 101        }
 102
 103        protected override TimeSpan DefaultCloseTimeout
 104        {
 105            get
 106            {
 2332107                if (_host != null)
 108                {
 2332109                    return _host.CloseTimeout;
 110                }
 0111                return ServiceDefaults.CloseTimeout;
 112            }
 113        }
 114
 115        protected override TimeSpan DefaultOpenTimeout
 116        {
 117            get
 118            {
 82119                if (_host != null)
 120                {
 72121                    return _host.OpenTimeout;
 122                }
 10123                return ServiceDefaults.OpenTimeout;
 124            }
 125        }
 126
 127        public IExtensionCollection<InstanceContext> Extensions
 128        {
 129            get
 130            {
 7586131                ThrowIfClosed();
 7586132                lock (ThisLock)
 133                {
 7586134                    if (_extensions == null)
 135                    {
 1985136                        _extensions = new ExtensionCollection<InstanceContext>(this, ThisLock);
 137                    }
 138
 7586139                    return _extensions;
 140                }
 7586141            }
 142        }
 143
 144        internal ICollection<IChannel> IncomingChannels
 145        {
 146            get
 147            {
 13148                ThrowIfClosed();
 13149                return _channels.IncomingChannels;
 150            }
 151        }
 152
 153        private bool IsBusy
 154        {
 155            get
 156            {
 2332157                if (State == CommunicationState.Closed)
 158                {
 0159                    return false;
 160                }
 161
 2332162                return _channels.IsBusy;
 163            }
 164        }
 165
 99166        public bool IsSingleton { get; internal set; }
 167
 168        internal ICollection<IChannel> OutgoingChannels
 169        {
 170            get
 171            {
 79172                ThrowIfClosed();
 79173                return _channels.OutgoingChannels;
 174            }
 175        }
 176
 177        public ServiceHostBase Host
 178        {
 179            get
 180            {
 0181                ThrowIfClosed();
 0182                return _host;
 183            }
 184        }
 185
 186        public int ManualFlowControlLimit
 187        {
 0188            get => EnsureQuotaThrottle().Limit;
 0189            set => EnsureQuotaThrottle().SetLimit(value);
 190        }
 191
 2536192        internal QuotaThrottle QuotaThrottle { get; private set; }
 193
 194        internal ServiceThrottle ServiceThrottle
 195        {
 0196            get { return _serviceThrottle; }
 197            set
 198            {
 2391199                ThrowIfDisposed();
 2391200                _serviceThrottle = value;
 2391201            }
 202        }
 203
 9891204        internal int InstanceContextManagerIndex { get; set; }
 205
 206        public SynchronizationContext SynchronizationContext
 207        {
 2536208            get { return _synchronizationContext; }
 209            set
 210            {
 0211                ThrowIfClosedOrOpened();
 0212                _synchronizationContext = value;
 0213            }
 214        }
 215
 216        internal new object ThisLock
 217        {
 21491218            get { return base.ThisLock; }
 219        }
 220
 221        protected override void OnAbort()
 222        {
 58223            _channels.Abort();
 58224            Unload();
 58225        }
 226
 227        internal Task CloseInputAsync(CancellationToken token)
 228        {
 0229            return _channels.CloseInputAsync(token);
 230        }
 231
 232        internal void BindRpc(MessageRpc rpc)
 233        {
 2536234            ThrowIfClosed();
 2536235            _channels.IncrementActivityCount();
 2536236            rpc.SuccessfullyBoundInstance = true;
 2536237        }
 238
 239        internal void BindIncomingChannel(ServiceChannel channel)
 240        {
 90241            ThrowIfDisposed();
 242
 90243            channel.InstanceContext = this;
 90244            IChannel proxy = (IChannel)channel.Proxy;
 90245            _channels.AddIncomingChannel(proxy);
 246
 247            // There's a race condition while on one thread we received a new request from underlying sessionful channel
 248            // and on another thread we just aborted the channel. So the channel will be added to the IncomingChannels l
 249            // ServiceChannelManager and never get a chance to be removed.
 90250            if (proxy != null)
 251            {
 90252                CommunicationState state = channel.State;
 90253                if (state == CommunicationState.Closing
 90254                    || state == CommunicationState.Closed
 90255                    || state == CommunicationState.Faulted)
 256                {
 0257                    _channels.RemoveChannel(proxy);
 258                }
 259            }
 90260        }
 261
 262        private void CloseIfNotBusy()
 263        {
 2332264            if (!(State != CommunicationState.Created && State != CommunicationState.Opening))
 265            {
 266                Fx.Assert(
 267                    "InstanceContext.CloseIfNotBusy: (this.State != CommunicationState.Created && this.State != Communic
 268            }
 269
 2332270            if (State != CommunicationState.Opened)
 271            {
 0272                return;
 273            }
 274
 2332275            if (IsBusy)
 276            {
 0277                return;
 278            }
 279
 2332280            if (_behavior.CanUnload(this) == false)
 281            {
 0282                return;
 283            }
 284
 285            try
 286            {
 287                // TODO: Make this call and it's chain async
 2332288                if (State == CommunicationState.Opened)
 289                {
 2332290                    CloseAsync().GetAwaiter().GetResult();
 291                }
 2332292            }
 293            catch (ObjectDisposedException e)
 294            {
 0295                DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
 0296            }
 297            catch (InvalidOperationException e)
 298            {
 0299                DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
 0300            }
 301            catch (CommunicationException e)
 302            {
 0303                DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
 0304            }
 305            catch (TimeoutException e)
 306            {
 307                //if (TD.CloseTimeoutIsEnabled())
 308                //{
 309                //    TD.CloseTimeout(e.Message);
 310                //}
 0311                DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
 0312            }
 2332313        }
 314
 315        private QuotaThrottle EnsureQuotaThrottle()
 316        {
 0317            lock (ThisLock)
 318            {
 0319                if (QuotaThrottle == null)
 320                {
 0321                    QuotaThrottle = new QuotaThrottle(ThisLock)
 0322                    {
 0323                        Owner = "InstanceContext"
 0324                    };
 325                }
 0326                return QuotaThrottle;
 327            }
 0328        }
 329
 330        internal void FaultInternal()
 331        {
 0332            Fault();
 0333        }
 334
 335        public object GetServiceInstance()
 336        {
 55337            return GetServiceInstance(null);
 338        }
 339
 340        public object GetServiceInstance(Message message)
 341        {
 2591342            lock (_serviceInstanceLock)
 343            {
 2591344                ThrowIfClosedOrNotOpen();
 345
 2591346                object current = _userObject;
 347
 2591348                if (current != null)
 349                {
 200350                    return current;
 351                }
 352
 2391353                if (_behavior == null)
 354                {
 0355                    Exception error = new InvalidOperationException(SR.SFxInstanceNotInitialized);
 0356                    if (message != null)
 357                    {
 0358                        throw TraceUtility.ThrowHelperError(error, message);
 359                    }
 0360                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(error);
 361                }
 362
 363                object newUserObject;
 2391364                if (message != null)
 365                {
 2391366                    newUserObject = _behavior.GetInstance(this, message);
 367                }
 368                else
 369                {
 0370                    newUserObject = _behavior.GetInstance(this);
 371                }
 2390372                if (newUserObject != null)
 373                {
 2390374                    SetUserObject(newUserObject);
 375                }
 376
 2390377                return newUserObject;
 378            }
 2590379        }
 380
 381        private void Load()
 382        {
 2473383            if (_behavior != null)
 384            {
 2473385                _behavior.Initialize(this);
 386            }
 387
 388            // TODO: Re-home InstanceContextManager and have a reference to it here.
 2473389            if (_host != null)
 390            {
 2463391                _host.BindInstance(this);
 392            }
 2473393        }
 394
 395        private static void NotifyEmpty(InstanceContext instanceContext)
 396        {
 2332397            if (instanceContext.AutoClose)
 398            {
 2332399                instanceContext.CloseIfNotBusy();
 400            }
 2332401        }
 402
 403        private static void NotifyIdle(InstanceContext instanceContext)
 404        {
 0405            instanceContext.CloseIfNotBusy();
 0406        }
 407
 408        protected override async Task OnCloseAsync(CancellationToken token)
 409        {
 2332410            await _channels.CloseAsync(token);
 2332411            Unload();
 2332412        }
 413
 414        protected override void OnClosed()
 415        {
 2390416            base.OnClosed();
 2390417            _serviceThrottle?.DeactivateInstanceContext();
 0418        }
 419
 420        protected override void OnFaulted()
 421        {
 0422            base.OnFaulted();
 423
 0424            if (IsSingleton && (_host != null))
 425            {
 426                // TODO: Create new mechanism to register fault event handlers
 427                //_host.FaultInternal();
 428            }
 0429        }
 430
 431        protected override Task OnOpenAsync(CancellationToken token)
 432        {
 2473433            return Task.CompletedTask;
 434        }
 435
 436        protected override void OnOpened()
 437        {
 2473438            base.OnOpened();
 2473439        }
 440
 441        protected override void OnOpening()
 442        {
 2473443            Load();
 2473444            base.OnOpening();
 2473445        }
 446
 447
 448        internal void ReleaseServiceInstance()
 449        {
 0450            ThrowIfDisposedOrNotOpen();
 0451            SetUserObject(null);
 0452        }
 453
 454        private void SetUserObject(object newUserObject)
 455        {
 4780456            if (_behavior != null && !IsWellKnown)
 457            {
 4780458                object oldUserObject = Interlocked.Exchange(ref _userObject, newUserObject);
 459
 4780460                if ((oldUserObject != null) && (_host != null) && !Equals(oldUserObject, _host.DisposableInstance))
 461                {
 2389462                    _behavior.ReleaseInstance(this, oldUserObject);
 463                }
 464            }
 4780465        }
 466
 467        internal void UnbindRpc(MessageRpc rpc)
 468        {
 2536469            if (rpc.InstanceContext == this && rpc.SuccessfullyBoundInstance)
 470            {
 2536471                _channels.DecrementActivityCount();
 472            }
 2536473        }
 474
 475        private void Unload()
 476        {
 2390477            SetUserObject(null);
 478
 479            // TODO: Re-home InstanceContextManager and have a reference to it here.
 2390480            if (_host != null)
 481            {
 2390482                _host.UnbindInstance(this);
 483            }
 2390484        }
 485    }
 486}