private async Task HandleAsync(TcpClient tcpClient) { string connectionDetails; try { connectionDetails = tcpClient.Client.RemoteEndPoint?.ToString() ?? "No details"; } catch (Exception exception) { connectionDetails = "Failed to get details"; _logger.LogError(exception, "Failed to get connection details."); } try { using var stream = tcpClient.GetStream(); using var sendLock = new SemaphoreSlimLock(); using var receiveLock = new SemaphoreSlimLock(); var connection = _protobufConnectionFactory.CreateProtobufConnection(stream) .WithLocking(sendLock, receiveLock); var task = _connectionHandler .HandleAsync(connection, _cts.Token) .HandleCancellationAsync(exception => { _logger.LogDebug( exception, "Cancellation request received for client: {ConnectionDetails}", connectionDetails); }) .HandleExceptionAsync <Exception>(exception => { _logger.LogError( exception, "Error happened while handling TCP connection: {ConnectionDetails}", connectionDetails); }); _connectionProcessors.Add(task); _connectionProcessors.RemoveAll(t => t.IsCompleted); await task.ConfigureAwait(false); } #pragma warning disable CA1031 // This method should not throw ANY exceptions, it is a top-level handler. catch (Exception exception) #pragma warning restore CA1031 { _logger.LogError( exception, "Error happened while creating TCP connection: {ConnectionDetails}", connectionDetails); } finally { tcpClient.Dispose(); } }
public async ValueTask <ConnectionWithDisconnect> ConnectAsync(CancellationToken cancellationToken) { var client = new TcpClient(); await client.ConnectAsync(_host, _port, cancellationToken).ConfigureAwait(false); var stream = client.GetStream(); var sendLock = new SemaphoreSlimLock(); var receiveLock = new SemaphoreSlimLock(); var connection = _factory.CreateProtobufConnection(stream) .WithLocking(sendLock, receiveLock); return(new ConnectionWithDisconnect(connection, async() => { receiveLock.Dispose(); sendLock.Dispose(); stream.Close(); await stream.DisposeAsync().ConfigureAwait(false); client.Dispose(); })); }