< Summary - CoreWCF Coverage — PR #1766

Information
Class: CoreWCF.Configuration.NetTcpFramingOptionsSetup
Assembly: CoreWCF.NetTcp
File(s): /home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.NetTcp/src/CoreWCF/Configuration/ServiceModelWebHostBuilderExtensions.cs
Line coverage
92%
Covered lines: 81
Uncovered lines: 7
Coverable lines: 88
Total lines: 250
Line coverage: 92%
Branch coverage
83%
Covered branches: 25
Total branches: 30
Branch coverage: 83.3%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.ctor(...)50%22100%
Configure(...)75%202078.78%
AddTcpListenOptionsToConnectionContext(...)100%44100%
ConvertExceptionsAndAddLogging(...)100%11100%
OnServiceBuilderOpening(...)100%11100%
UpdateServiceBuilderBaseAddresses()100%44100%

File(s)

/home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.NetTcp/src/CoreWCF/Configuration/ServiceModelWebHostBuilderExtensions.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.Net;
 7using System.Net.Sockets;
 8using System.Web.Services.Description;
 9using CoreWCF.Channels;
 10using CoreWCF.Channels.Framing;
 11using Microsoft.AspNetCore.Connections;
 12using Microsoft.AspNetCore.Hosting;
 13using Microsoft.AspNetCore.Hosting.Server;
 14using Microsoft.AspNetCore.Server.Kestrel.Core;
 15using Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets;
 16using Microsoft.Extensions.DependencyInjection;
 17using Microsoft.Extensions.DependencyInjection.Extensions;
 18using Microsoft.Extensions.Hosting;
 19using Microsoft.Extensions.Logging;
 20using Microsoft.Extensions.Options;
 21
 22namespace CoreWCF.Configuration
 23{
 24    public static class ServiceModelWebHostBuilderExtensions
 25    {
 26        public static IWebHostBuilder UseNetTcp(this IWebHostBuilder webHostBuilder)
 27        {
 28            // Using default port for net.tcp
 29            return webHostBuilder.UseNetTcp(808);
 30        }
 31
 32        public static IWebHostBuilder UseNetTcp(this IWebHostBuilder webHostBuilder, int port)
 33        {
 34            return webHostBuilder.UseNetTcp(IPAddress.Any, port);
 35        }
 36
 37        public static IWebHostBuilder UseNetTcp(this IWebHostBuilder webHostBuilder, IPAddress ipAddress)
 38        {
 39            return webHostBuilder.UseNetTcp(ipAddress, 808);
 40        }
 41
 42        public static IWebHostBuilder UseNetTcp(this IWebHostBuilder webHostBuilder, IPAddress ipAddress, int port)
 43        {
 44            webHostBuilder.AddNetTcpRequiredServices()
 45                          .ConfigureNetTcp(options =>
 46                          {
 47                              var uriBuilder = new UriBuilder("net.tcp", ipAddress.ToString(), port);
 48                              options.Listen(uriBuilder.Uri);
 49                          });
 50            return webHostBuilder;
 51        }
 52
 53        private static IWebHostBuilder AddNetTcpRequiredServices(this IWebHostBuilder webHostBuilder)
 54        {
 55            webHostBuilder.ConfigureServices(services =>
 56            {
 57                services.AddNetFramingServices();
 58                services.TryAddEnumerable(ServiceDescriptor.Singleton<IHostedService, NetTcpHostedService>());
 59                services.TryAddSingleton<NetTcpFramingOptionsSetup>();
 60                services.TryAddEnumerable(ServiceDescriptor.Singleton<IConfigureOptions<KestrelServerOptions>, NetTcpFra
 61                services.TryAddEnumerable(ServiceDescriptor.Singleton<IConfigureOptions<NetTcpOptions>, NetTcpServerOpti
 62                services.TryAddSingleton<SocketTransportFactory>();
 63            });
 64            return webHostBuilder;
 65        }
 66
 67        public static IWebHostBuilder UseNetTcp(this IWebHostBuilder webHostBuilder, Action<NetTcpOptions> options)
 68        {
 69            webHostBuilder.AddNetTcpRequiredServices()
 70                          .ConfigureNetTcp(options);
 71            return webHostBuilder;
 72        }
 73
 74        public static IWebHostBuilder ConfigureNetTcp(this IWebHostBuilder webHostBuilder, Action<NetTcpOptions> options
 75        {
 76            return webHostBuilder.ConfigureServices(services =>
 77            {
 78                services.Configure(options);
 79            });
 80        }
 81
 82        private static IServiceCollection AddNetTcpServices(this IServiceCollection services, IPEndPoint endPoint)
 83        {
 84            services.Configure<NetTcpFramingOptions>(o =>
 85            {
 86                o.EndPoints.Add(endPoint);
 87            });
 88
 89            return services;
 90        }
 91    }
 92
 93    // Exposes options for how to bind. This could include port sharing in the future
 94    internal class NetTcpFramingOptions
 95    {
 96        public List<IPEndPoint> EndPoints { get; } = new List<IPEndPoint>();
 97    }
 98
 99    internal class NetTcpFramingOptionsSetup : IConfigureOptions<KestrelServerOptions>
 100    {
 101        private readonly ILogger<NetTcpFramingOptions> _logger;
 102        private readonly ILogger<FramingConnection> _framingConnectionLogger;
 103        private readonly IServiceProvider _serviceProvider;
 104        private readonly NetTcpOptions _options;
 105        private readonly IServiceBuilder _serviceBuilder;
 106
 80107        public NetTcpFramingOptionsSetup(IOptions<NetTcpOptions> options, IServiceBuilder serviceBuilder, ILogger<NetTcp
 108        {
 80109            _options = options.Value ?? new NetTcpOptions();
 80110            _serviceBuilder = serviceBuilder;
 80111            _logger = logger;
 80112            _framingConnectionLogger = framingConnectionLogger;
 80113            _serviceProvider = serviceProvider;
 80114        }
 115
 320116        public List<ListenOptions> ListenOptions { get; } = new List<ListenOptions>();
 117
 160118        public bool ConfigureCalled { get; set; }
 119
 120        public void Configure(KestrelServerOptions options)
 121        {
 80122            ConfigureCalled = true;
 80123            options.ApplicationServices = _serviceProvider;
 320124            foreach(var tcpListenOptions in _options.CodeBackedListenOptions)
 125            {
 80126                var baseAddress = tcpListenOptions.BaseAddress;
 80127                IPAddress listenAddress = null;
 80128                if (baseAddress.HostNameType == UriHostNameType.IPv4 || baseAddress.HostNameType == UriHostNameType.IPv6
 129                {
 77130                    if (IPAddress.TryParse(baseAddress.DnsSafeHost, out listenAddress))
 131                    {
 77132                        if (listenAddress.AddressFamily == AddressFamily.InterNetwork && !Socket.OSSupportsIPv4)
 133                        {
 0134                            _logger.LogError("NetTcp listen uri specified the IPv4 hostname \"{HostName}\" and the OS do
 0135                            continue;
 136                        }
 77137                        if (listenAddress.AddressFamily == AddressFamily.InterNetworkV6 && !Socket.OSSupportsIPv6)
 138                        {
 0139                            _logger.LogError("NetTcp listen uri specified the IPv6 hostname \"{HostName}\" and the OS do
 0140                            continue;
 141                        }
 142                    }
 143                }
 3144                else if (baseAddress.HostNameType == UriHostNameType.Dns)
 145                {
 3146                    if (Socket.OSSupportsIPv6)
 147                    {
 3148                        listenAddress = IPAddress.IPv6Any;
 149                    }
 150                    else
 151                    {
 0152                        listenAddress = IPAddress.Any;
 153                    }
 154                }
 155                else
 156                {
 0157                    _logger.LogError("NetTcp listen uri specified an unusable hostname \"{HostName}\"", baseAddress.DnsS
 0158                    continue;
 159                }
 160
 80161                IPEndPoint endpoint = new IPEndPoint(listenAddress, baseAddress.Port);
 80162                options.Listen(endpoint, builder =>
 80163                {
 80164                    AddTcpListenOptionsToConnectionContext(builder, tcpListenOptions);
 80165                    builder.Use(ConvertExceptionsAndAddLogging);
 80166                    builder.UseConnectionHandler<NetMessageFramingConnectionHandler>();
 80167                    // Save the ListenOptions to be able to get final port number for adding BaseAddresses later
 80168                    ListenOptions.Add(builder);
 80169                    // Save the Kestrel ListenOptions in the TcpListenOptions to enable getting the final listening IPEn
 80170                    // This helps to get the port number being used if specified as 0, after the server has started.
 80171                    tcpListenOptions.ListenOptions = builder;
 160172                });
 173            }
 174            //foreach (IPEndPoint endpoint in _options.EndPoints)
 175            //{
 176            //    options.Listen(endpoint, builder =>
 177            //    {
 178            //        builder.Use(ConvertExceptionsAndAddLogging);
 179            //        builder.UseConnectionHandler<NetMessageFramingConnectionHandler>();
 180            //        // Save the ListenOptions to be able to get final port number for adding BaseAddresses later
 181            //        ListenOptions.Add(builder);
 182            //    });
 183            //}
 184
 80185            _serviceBuilder.Opening += OnServiceBuilderOpening;
 80186        }
 187
 188        private void AddTcpListenOptionsToConnectionContext(ListenOptions builder, TcpListenOptions tcpListenOptions)
 189        {
 80190            builder.Use(next =>
 80191            {
 80192                tcpListenOptions.Use(innerNext =>
 80193                {
 80194                    return (ConnectionContext context) =>
 80195                    {
 79196                        context.Features.Set<NetFramingListenOptions>(tcpListenOptions);
 79197                        return innerNext(context);
 80198                    };
 80199                });
 80200                tcpListenOptions.Use(_ =>
 80201                {
 80202                    return (ConnectionContext context) =>
 80203                    {
 79204                        return next(context);
 80205                    };
 80206                });
 80207                var tcpListenOptionsMiddleware = ((IConnectionBuilder)tcpListenOptions).Build();
 80208                return tcpListenOptionsMiddleware;
 80209            });
 80210        }
 211
 212        private ConnectionDelegate ConvertExceptionsAndAddLogging(ConnectionDelegate next)
 213        {
 80214            return (ConnectionContext context) =>
 80215            {
 79216                var logger = new ConnectionIdWrappingLogger(_framingConnectionLogger, context.ConnectionId);
 79217                context.Features.Set<ILogger>(logger);
 80218
 80219                //TODO: Add a public api mechanism to enable connection logging in RELEASE build
 80220#if DEBUG
 80221                context.Transport = new NetTcpExceptionConvertingDuplexPipe(new LoggingDuplexPipe(context.Transport, log
 80222#else
 79223                context.Transport = new NetTcpExceptionConvertingDuplexPipe(context.Transport);
 80224#endif
 79225                return next(context);
 80226            };
 227        }
 228
 229        private void OnServiceBuilderOpening(object sender, EventArgs e)
 230        {
 80231            UpdateServiceBuilderBaseAddresses();
 80232        }
 233
 234        internal void UpdateServiceBuilderBaseAddresses()
 235        {
 320236            foreach (ListenOptions listenOptions in ListenOptions)
 237            {
 80238                IPEndPoint endpoint = listenOptions.IPEndPoint;
 80239                string address = endpoint.Address.ToString();
 80240                if (endpoint.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6)
 4241                    address = $"[{address}]";
 80242                var baseAddress = new Uri($"net.tcp://{address}:{endpoint.Port}/");
 80243                _logger.LogDebug("Adding base address {baseAddress} to ServiceBuilderOptions", baseAddress);
 80244                _serviceBuilder.BaseAddresses.Add(baseAddress);
 245            }
 246
 80247            ListenOptions.Clear();
 80248        }
 249    }
 250}