public static async Task RunServerAsync(IConnectionListener listener, ConnectionDelegate connectionDelegate, CancellationToken cancellationToken = default) { ValueTask unbindTask = default; cancellationToken.Register(() => { unbindTask = listener.UnbindAsync(); }); while (true) { var connection = await listener.AcceptAsync(cancellationToken); if (connection == null) { break; } _ = Task.Run(async() => { try { await connectionDelegate(connection); } finally { await connection.DisposeAsync(); } }); } await unbindTask; // TODO: Wait for opened connections to close await listener.DisposeAsync(); }
public ValueTask DisposeAsync() => _connectionListener.DisposeAsync();
public override async Task StopAsync(CancellationToken cancellationToken) { await _connectionListener.DisposeAsync(); }
public async Task RunListenerAsync(IConnectionListener listener, ConnectionDelegate connectionDelegate, CancellationToken cancellationToken = default) { var unbindTask = new TaskCompletionSource <object>(); var connections = new ConcurrentDictionary <string, (ConnectionContext Connection, Task ExecutionTask)>(); cancellationToken.Register(async() => { try { await listener.UnbindAsync(); } finally { unbindTask.TrySetResult(null); } }); async Task ExecuteConnectionAsync(ConnectionContext connection) { await Task.Yield(); try { await connectionDelegate(connection); } catch (ConnectionAbortedException) { // Don't let connection aborted exceptions out } catch (Exception ex) { _logger.LogError(ex, "Unexpected exception from connection {ConnectionId}", connection.ConnectionId); } finally { await connection.DisposeAsync(); // Remove the connection from tracking connections.TryRemove(connection.ConnectionId, out _); } } while (true) { try { var connection = await listener.AcceptAsync(cancellationToken); if (connection == null) { // Null means we don't have anymore connections break; } connections[connection.ConnectionId] = (connection, ExecuteConnectionAsync(connection)); } catch (OperationCanceledException) { // The accept loop was cancelled break; } } // Wait for the listener to close, no new connections will be established await unbindTask.Task; // TODO: Give connections a chance to close gracefully var tasks = new List <Task>(connections.Count); // Abort all connections still in flight foreach (var pair in connections) { pair.Value.Connection.Abort(); tasks.Add(pair.Value.ExecutionTask); } await Task.WhenAll(tasks); await listener.DisposeAsync(); }