Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix for exceptions thrown on an unexpected client disconnection. #83

Open
wants to merge 4 commits into
base: dotnetcore3
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 17 additions & 6 deletions src/WebsocketManager/ConnectionManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,30 @@ public string GetId(WebSocket socket)
{
return _sockets.FirstOrDefault(p => p.Value == socket).Key;
}

public void AddSocket(WebSocket socket)
{
_sockets.TryAdd(CreateConnectionId(), socket);
}

public async Task RemoveSocket(string id)
public async Task CloseAndRemoveSocket(string id)
{
WebSocket socket;
_sockets.TryRemove(id, out socket);
if (_sockets.TryRemove(id, out var socket))
{
await socket.CloseOutputAsync(closeStatus: WebSocketCloseStatus.NormalClosure,
statusDescription: "Closed by the ConnectionManager",
cancellationToken: CancellationToken.None);
}
}

public Task RemoveSocket(string id)
{
if (_sockets.TryRemove(id, out var socket))
{
socket.Dispose();
}

await socket.CloseAsync(closeStatus: WebSocketCloseStatus.NormalClosure,
statusDescription: "Closed by the ConnectionManager",
cancellationToken: CancellationToken.None);
return Task.CompletedTask;
}

private string CreateConnectionId()
Expand Down
5 changes: 5 additions & 0 deletions src/WebsocketManager/Handler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ public virtual async Task OnConnected(WebSocket socket)
WebSocketConnectionManager.AddSocket(socket);
}

public virtual async Task OnCloseConnection(WebSocket socket)
{
await WebSocketConnectionManager.CloseAndRemoveSocket(WebSocketConnectionManager.GetId(socket));
}

public virtual async Task OnDisconnected(WebSocket socket)
{
await WebSocketConnectionManager.RemoveSocket(WebSocketConnectionManager.GetId(socket));
Expand Down
48 changes: 29 additions & 19 deletions src/WebsocketManager/Middleware.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,30 +20,40 @@ public WebSocketManagerMiddleware(RequestDelegate next,

public async Task Invoke(HttpContext context)
{
if(!context.WebSockets.IsWebSocketRequest)
return;

var socket = await context.WebSockets.AcceptWebSocketAsync();
await _webSocketHandler.OnConnected(socket);

await Receive(socket, async(result, buffer) =>
if (context.WebSockets.IsWebSocketRequest)
{
if(result.MessageType == WebSocketMessageType.Text)
{
await _webSocketHandler.ReceiveAsync(socket, result, buffer);
return;
}
var socket = await context.WebSockets.AcceptWebSocketAsync();
await _webSocketHandler.OnConnected(socket);

else if(result.MessageType == WebSocketMessageType.Close)
try
{
await _webSocketHandler.OnDisconnected(socket);
return;
await Receive(socket, async(result, buffer) =>
{
if (result.MessageType == WebSocketMessageType.Text)
{
await _webSocketHandler.ReceiveAsync(socket, result, buffer);
}
else if(result.MessageType == WebSocketMessageType.Close)
{
await _webSocketHandler.OnCloseConnection(socket);
}
});
}
catch (WebSocketException e)
{
if (e.WebSocketErrorCode == WebSocketError.ConnectionClosedPrematurely)
{
await _webSocketHandler.OnDisconnected(socket);
return;
}

});

//TODO - investigate the Kestrel exception thrown when this is the last middleware
//await _next.Invoke(context);
throw;
}
}
else
{
await _next.Invoke(context);
}
}

private async Task Receive(WebSocket socket, Action<WebSocketReceiveResult, byte[]> handleMessage)
Expand Down