< Summary - CoreWCF Coverage — PR #1766

Information
Class: CoreWCF.Channels.NamedPipeConnection
Assembly: CoreWCF.NetNamedPipe
File(s): /home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.NetNamedPipe/src/CoreWCF/Channels/NamedPipeConnection.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 55
Coverable lines: 55
Total lines: 142
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 4
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.cctor()100%110%
.ctor(...)100%110%
ConfigureContextLogging()100%110%
StartDispatching()100%110%
ThreadPoolCallback(...)100%110%
ExecuteAsync()0%220%
BeginConnectionScope()0%220%
RequestClose()100%110%
CloseAsync()100%110%
Complete()100%110%

File(s)

/home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.NetNamedPipe/src/CoreWCF/Channels/NamedPipeConnection.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.Threading;
 6using System.Threading.Tasks;
 7using CoreWCF.Channels.Framing;
 8using Microsoft.AspNetCore.Connections;
 9using Microsoft.Extensions.Logging;
 10
 11namespace CoreWCF.Channels
 12{
 13    internal class NamedPipeConnection
 14    {
 015        private static WaitCallback s_ThreadPoolCallback = ThreadPoolCallback;
 16
 17        private ConnectionDelegate _connectionDelegate;
 018        private readonly CancellationTokenSource _connectionClosingCts = new CancellationTokenSource();
 019        private readonly TaskCompletionSource<object> _completionTcs = new TaskCompletionSource<object>(TaskCreationOpti
 20        protected readonly long _id;
 21        protected readonly TransportConnectionManager _transportConnectionManager;
 22
 023        public NamedPipeConnection(long id, NamedPipeConnectionContext connectionContext, ConnectionDelegate connectionD
 24        {
 025            _id = id;
 026            ConnectionContext = connectionContext;
 027            _transportConnectionManager = transportConnectionManager;
 028            _connectionDelegate = connectionDelegate;
 029            Logger = logger;
 030            ConnectionClosedRequested = _connectionClosingCts.Token;
 031            ConfigureContextLogging();
 032        }
 33
 34        private void ConfigureContextLogging()
 35        {
 36#if DEBUG
 37            ConnectionContext.Transport = new NamedPipeExceptionConvertingDuplexPipe(new LoggingDuplexPipe(ConnectionCon
 38#else
 039            ConnectionContext.Transport = new NamedPipeExceptionConvertingDuplexPipe(ConnectionContext.Transport);
 40#endif
 041        }
 42
 043        public Task ExecutionTask => _completionTcs.Task;
 44
 045        public CancellationToken ConnectionClosedRequested { get; set; }
 46
 047        public NamedPipeConnectionContext ConnectionContext { get; }
 48
 049        private NetNamedPipeTrace Logger { get; }
 50
 51        internal void StartDispatching()
 52        {
 053            ThreadPool.UnsafeQueueUserWorkItem(s_ThreadPoolCallback, this);
 054        }
 55
 56        internal static void ThreadPoolCallback(object state)
 57        {
 058            _ = ((NamedPipeConnection)state).ExecuteAsync();
 059        }
 60
 61        internal async Task ExecuteAsync()
 62        {
 063            var connectionContext = ConnectionContext;
 64
 65            try
 66            {
 067                connectionContext.Start();
 068                Logger.ConnectionStart(connectionContext.ConnectionId);
 69
 070                using (BeginConnectionScope())
 71                {
 72                    try
 73                    {
 074                        await _connectionDelegate(connectionContext);
 075                    }
 076                    catch (Exception ex)
 77                    {
 078                        Logger.LogError(0, ex, "Unhandled exception while processing {ConnectionId}.", connectionContext
 079                    }
 080                }
 81            }
 82            finally
 83            {
 084                Logger.ConnectionStop(connectionContext.ConnectionId);
 85
 86                // Dispose the transport connection, this needs to happen before removing it from the
 87                // connection manager so that we only signal completion of this connection after the transport
 88                // is properly torn down.
 089                await connectionContext.DisposeAsync();
 90
 091                _transportConnectionManager.RemoveConnection(_id);
 92            }
 093        }
 94
 95        protected IDisposable BeginConnectionScope()
 96        {
 097            if (Logger.IsEnabled(LogLevel.Critical))
 98            {
 099                return Logger.BeginScope(new ConnectionLogScope(ConnectionContext.ConnectionId));
 100            }
 101
 0102            return null;
 103        }
 104
 105        public void RequestClose()
 106        {
 107            try
 108            {
 0109                _ = CloseAsync();
 0110                _connectionClosingCts.Cancel();
 0111            }
 0112            catch (ObjectDisposedException)
 113            {
 114                // There's a race where the token could be disposed
 115                // swallow the exception and no-op
 0116            }
 0117        }
 118
 119        private async Task CloseAsync()
 120        {
 121            try
 122            {
 0123                await ConnectionContext.DisposeAsync();
 0124            }
 0125            catch (Exception ex)
 126            {
 0127                Logger.LogError(0, ex, "Error while closing connection {ConnectionId}.", ConnectionContext.ConnectionId)
 0128            }
 129            finally
 130            {
 0131                Complete();
 132            }
 0133        }
 134
 135        public void Complete()
 136        {
 0137            _completionTcs.TrySetResult(null);
 138
 0139            _connectionClosingCts.Dispose();
 0140        }
 141    }
 142}