< Summary - CoreWCF Coverage — PR #1766

Information
Class: CoreWCF.Channels.NetTcpHostedService
Assembly: CoreWCF.NetTcp
File(s): /home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.NetTcp/src/CoreWCF/Channels/NetTcpHostedService.cs
Line coverage
57%
Covered lines: 26
Uncovered lines: 19
Coverable lines: 45
Total lines: 136
Line coverage: 57.7%
Branch coverage
50%
Covered branches: 12
Total branches: 24
Branch coverage: 50%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.ctor(...)75%44100%
Init()50%4480%
StartAsync()16.66%6623.07%
StopAsync(...)83.33%6683.33%
Dispose()100%110%
DisposeAsync()100%11100%
UpdateServerAddressesFeature()25%4416.66%

File(s)

/home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.NetTcp/src/CoreWCF/Channels/NetTcpHostedService.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.Linq;
 7using System.Runtime.InteropServices;
 8using System.Threading;
 9using System.Threading.Tasks;
 10using CoreWCF.Configuration;
 11using Microsoft.AspNetCore.Hosting.Server;
 12using Microsoft.AspNetCore.Hosting.Server.Features;
 13using Microsoft.AspNetCore.Server.Kestrel.Core;
 14using Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets;
 15using Microsoft.Extensions.DependencyInjection;
 16using Microsoft.Extensions.Hosting;
 17using Microsoft.Extensions.Logging;
 18using Microsoft.Extensions.Options;
 19
 20namespace CoreWCF.Channels
 21{
 22    internal class NetTcpHostedService : IHostedService, IAsyncDisposable, IDisposable
 23    {
 15824        private static bool s_isNetFramework => RuntimeInformation.FrameworkDescription.StartsWith(".NET Framework", Str
 25
 26        private readonly NetTcpOptions _serverOptions;
 27        private readonly IServiceBuilder _serviceBuilder;
 28        private readonly ILogger<NetTcpHostedService> _logger;
 29        private readonly IServiceProvider _serviceProvider;
 30        private KestrelServer _kestrel;
 31        private CancellationTokenRegistration _applicationStartedRegistration;
 32        private bool _started;
 33
 8034        public NetTcpHostedService(IOptions<NetTcpOptions> options, IServer server, IServiceBuilder serviceBuilder, ILog
 35        {
 36            // We request the IServer in the constructor to trigger the constructor of the implementation. If the implem
 37            // is KestrelServer it will run NetTcpFramingOptionsSetup.Configure, which we use to detect the server is Ke
 38            // We can't just examine the type as we wrap it so we can throw any startup exceptions using WrappingIServer
 39            // The IServer will have already been started on asp.net core 2.1, but later versions start it after IHosted
 40            _ = server;
 8041            _serverOptions = options.Value ?? new NetTcpOptions();
 8042            _serviceBuilder = serviceBuilder;
 8043            _logger = logger;
 8044            _serviceProvider = serviceProvider;
 8045            IApplicationLifetime appLifetime = _serviceProvider.GetRequiredService<IApplicationLifetime>();
 46            // asp.net core 2.1 executes the ApplicationStarted registered callback before it starts hosted services
 8047            if (!s_isNetFramework)
 48            {
 8049                _applicationStartedRegistration = appLifetime.ApplicationStarted.Register(UpdateServerAddressesFeature);
 50            }
 8051            Init();
 8052        }
 53
 31854        public bool KestrelAlreadyInUse { get; private set; }
 55
 56        private void Init()
 57        {
 58            // Check if Kestrel is already being used and if it is, it was already configured so there's nothing to do.
 32259            var netTcpFramingOptionsSetup = _serviceProvider.GetServices<IConfigureOptions<KestrelServerOptions>>().Sing
 8060            if (netTcpFramingOptionsSetup != null && netTcpFramingOptionsSetup.ConfigureCalled)
 61            {
 8062                KestrelAlreadyInUse = true;
 8063                return;
 64            }
 065        }
 66
 67        public async Task StartAsync(CancellationToken cancellationToken)
 68        {
 8069            _started = true;
 16070            if (KestrelAlreadyInUse) return;
 71
 072            var transportFactory = _serviceProvider.GetRequiredService<SocketTransportFactory>();
 073            _kestrel = ActivatorUtilities.CreateInstance(_serviceProvider, typeof(KestrelServer), transportFactory) as K
 74
 075            await _kestrel.StartAsync<int>(null, cancellationToken);
 76
 77            // As we don't register the ApplicationStarted callback when running on .NET Framework, and we know that the
 78            // has already started before us, we can fixup the server addresses now.
 079            if (s_isNetFramework)
 80            {
 081                UpdateServerAddressesFeature();
 82                // Need to update base addresses as ServiceBuilder was opened by wrapping WrappingIServer
 083                var framingOptionsSetup = _serviceProvider.GetRequiredService<NetTcpFramingOptionsSetup>();
 084                framingOptionsSetup.UpdateServiceBuilderBaseAddresses();
 085                var serviceBuilder = _serviceProvider.GetRequiredService<IServiceBuilder>() as ICommunicationObject;
 086                if (serviceBuilder.State == CommunicationState.Opened)
 87                {
 88                    // Need to resolve the UriPrefixTable as the service builder was already opened
 89                    // before we could hook up NetMessageFramingConnectionHandler.OnServiceBuilderOpened
 90                    // to be called when the service builder is opened. As UriPrefixTable is internal
 91                    // to NetFramingBase, it was also registered as its implemented interface type which
 92                    // allows us to resolve it here.
 093                    _ = _serviceProvider.GetRequiredService<IEnumerable<KeyValuePair<BaseUriWithWildcard, HandshakeDeleg
 94                }
 95            }
 8096        }
 97
 98        public Task StopAsync(CancellationToken cancellationToken)
 99        {
 234100            if (!_started) return Task.CompletedTask;
 78101            _started = false;
 78102            if (!s_isNetFramework)
 103            {
 78104                _applicationStartedRegistration.Dispose();
 105            }
 106
 156107            if (KestrelAlreadyInUse) return Task.CompletedTask;
 0108            return _kestrel.StopAsync(cancellationToken);
 109        }
 110
 111        public void Dispose()
 112        {
 113            // No need to check if StopAsync has been called as it is a no-op after the first call
 0114            StopAsync(default).GetAwaiter().GetResult();
 0115        }
 116
 117        public ValueTask DisposeAsync()
 118        {
 119            // No need to check if StopAsync has been called as it is a no-op after the first call
 78120            return new ValueTask(StopAsync(default));
 121        }
 122
 123        private void UpdateServerAddressesFeature()
 124        {
 125            // This method needs to be called from appLifetime.ApplicationStarted otherwise an IServer might try to list
 126            // the address that Kestrel is listening on. It's not needed if Kestrel is the IServer implementation for th
 160127            if (KestrelAlreadyInUse) return;
 0128            var kestrelServerAddresses = _kestrel.Features.Get<IServerAddressesFeature>();
 0129            var serverAddressesFeature = _serviceProvider.GetRequiredService<IServer>().Features.Get<IServerAddressesFea
 0130            foreach (var address in kestrelServerAddresses.Addresses)
 131            {
 0132                serverAddressesFeature.Addresses.Add(address);
 133            }
 0134        }
 135    }
 136}