public async Task DefaultWebSocketHandlerOperationsNoopAfterClose() { var handler = new DefaultWebSocketHandler(maxIncomingMessageSize: null, logger: new Mock<ILogger>().Object); var initialWebSocket = new Mock<WebSocket>(); initialWebSocket.Setup(w => w.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, "", CancellationToken.None)) .Returns(TaskAsyncHelper.Empty); initialWebSocket.Setup(w => w.CloseAsync(WebSocketCloseStatus.NormalClosure, "", CancellationToken.None)) .Returns(TaskAsyncHelper.Empty); initialWebSocket.Setup(w => w.ReceiveAsync(It.IsAny<ArraySegment<byte>>(), CancellationToken.None)) .Returns(Task.FromResult(new WebSocketReceiveResult(0, WebSocketMessageType.Close, endOfMessage: true))); await handler.ProcessWebSocketRequestAsync(initialWebSocket.Object, CancellationToken.None); // Swap the socket here so we can verify what happens after the task returns var afterWebSocket = new Mock<WebSocket>(); handler.WebSocket = afterWebSocket.Object; await handler.Send(new ArraySegment<byte>(Encoding.UTF8.GetBytes("Hello World"))); await handler.CloseAsync(); afterWebSocket.Verify(m => m.State, Times.Never()); afterWebSocket.Verify(m => m.SendAsync(It.IsAny<ArraySegment<byte>>(), WebSocketMessageType.Text, true, CancellationToken.None), Times.Never()); afterWebSocket.Verify(m => m.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, "", CancellationToken.None), Times.Never()); }
private void RunWebSocketHandler(DefaultWebSocketHandler handler, CancellationTokenSource cts) { // async void methods are not supported in ASP.NET and they throw a InvalidOperationException. Task.Run(async () => { try { await _callback(handler); } catch { // This error was already handled by other layers // we can no-op here so we don't cause an unobserved exception } // Always try to close async, if the websocket already closed // then this will no-op await handler.CloseAsync(); // Cancel the token cts.Cancel(); }); }