diff --git a/src/Microsoft.AspNetCore.Sockets.Client.Http/WebSocketsTransport.cs b/src/Microsoft.AspNetCore.Sockets.Client.Http/WebSocketsTransport.cs index 5f7345162f..7177993346 100644 --- a/src/Microsoft.AspNetCore.Sockets.Client.Http/WebSocketsTransport.cs +++ b/src/Microsoft.AspNetCore.Sockets.Client.Http/WebSocketsTransport.cs @@ -67,6 +67,7 @@ namespace Microsoft.AspNetCore.Sockets.Client // https://github.com/SignalR/SignalR/blob/1fba14fa3437e24c204dfaf8a18db3fce8acad3c/src/Microsoft.AspNet.SignalR.Core/Owin/WebSockets/WebSocketHandler.cs#L248-L251 Running = Task.WhenAll(sendTask, receiveTask).ContinueWith(t => { + _webSocket.Dispose(); _logger.TransportStopped(_connectionId, t.Exception?.InnerException); _application.Out.TryComplete(t.IsFaulted ? t.Exception.InnerException : null); return t; @@ -221,7 +222,6 @@ namespace Microsoft.AspNetCore.Sockets.Client _logger.TransportStopping(_connectionId); await CloseWebSocket(); - _webSocket.Dispose(); try { @@ -242,7 +242,13 @@ namespace Microsoft.AspNetCore.Sockets.Client if (_webSocket.State != WebSocketState.Closed) { _logger.ClosingWebSocket(_connectionId); - await _webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, null, CancellationToken.None); + + // We intentionally don't pass _transportCts.Token to CloseOutputAsync. The token can be cancelled + // for reasons not related to webSocket in which case we would not close the websocket gracefully. + await _webSocket.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, null, CancellationToken.None); + + // shutdown the transport after a timeout in case the server does not send close frame + _transportCts.CancelAfter(TimeSpan.FromSeconds(5)); } } catch (Exception ex) diff --git a/test/Microsoft.AspNetCore.SignalR.Tests/EndToEndTests.cs b/test/Microsoft.AspNetCore.SignalR.Tests/EndToEndTests.cs index b67b3d1442..004653180b 100644 --- a/test/Microsoft.AspNetCore.SignalR.Tests/EndToEndTests.cs +++ b/test/Microsoft.AspNetCore.SignalR.Tests/EndToEndTests.cs @@ -42,6 +42,17 @@ namespace Microsoft.AspNetCore.SignalR.Tests _serverFixture = serverFixture; } + [Fact] + public async Task CanStartConnectionUsingDefaultTransport() + { + var url = _serverFixture.BaseUrl + "/echo"; + // The test should connect to the server using WebSockets transport on Windows 8 and newer. + // On Windows 7/2008R2 it should use ServerSentEvents transport to connect to the server. + var connection = new HttpConnection(new Uri(url)); + await connection.StartAsync().OrTimeout(); + await connection.DisposeAsync().OrTimeout(); + } + [ConditionalFact] [OSSkipCondition(OperatingSystems.Windows, WindowsVersions.Win7, WindowsVersions.Win2008R2, SkipReason = "No WebSockets Client for this platform")] public async Task WebSocketsTest()