From 3e70ae93ff4ad94aebfa57949f611945dbc6a89b Mon Sep 17 00:00:00 2001 From: Kenneth Pouncey Date: Mon, 16 Nov 2020 11:13:23 +0100 Subject: [PATCH 1/8] [browser][websocket] Throw OperationCanceledException on connect if cancel was requested before. --- .../src/System/Net/WebSockets/WebSocketHandle.Browser.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libraries/System.Net.WebSockets.Client/src/System/Net/WebSockets/WebSocketHandle.Browser.cs b/src/libraries/System.Net.WebSockets.Client/src/System/Net/WebSockets/WebSocketHandle.Browser.cs index 97bdfdf28d84a0..0b216531563820 100644 --- a/src/libraries/System.Net.WebSockets.Client/src/System/Net/WebSockets/WebSocketHandle.Browser.cs +++ b/src/libraries/System.Net.WebSockets.Client/src/System/Net/WebSockets/WebSocketHandle.Browser.cs @@ -31,6 +31,7 @@ public async Task ConnectAsync(Uri uri, CancellationToken cancellationToken, Cli { try { + cancellationToken.ThrowIfCancellationRequested(); // avoid allocating a WebSocket object if cancellation was requested before connect CancellationTokenSource? linkedCancellation; CancellationTokenSource externalAndAbortCancellation; if (cancellationToken.CanBeCanceled) // avoid allocating linked source if external token is not cancelable @@ -61,7 +62,8 @@ public async Task ConnectAsync(Uri uri, CancellationToken cancellationToken, Cli Abort(); - if (exc is WebSocketException) + if (exc is WebSocketException || + (exc is OperationCanceledException && cancellationToken.IsCancellationRequested)) { throw; } From ba48ff519115e7c04a63f8ad8163063e7944b5c5 Mon Sep 17 00:00:00 2001 From: Larry Ewing Date: Mon, 16 Nov 2020 13:41:29 -0600 Subject: [PATCH 2/8] try to handle cancellation in connect stage --- .../BrowserWebSockets/BrowserWebSocket.cs | 22 ++++++++++++++++--- .../tests/ConnectTest.cs | 2 +- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/libraries/System.Net.WebSockets.Client/src/System/Net/WebSockets/BrowserWebSockets/BrowserWebSocket.cs b/src/libraries/System.Net.WebSockets.Client/src/System/Net/WebSockets/BrowserWebSockets/BrowserWebSocket.cs index b767c3149bee43..0609669c2be47a 100644 --- a/src/libraries/System.Net.WebSockets.Client/src/System/Net/WebSockets/BrowserWebSockets/BrowserWebSocket.cs +++ b/src/libraries/System.Net.WebSockets.Client/src/System/Net/WebSockets/BrowserWebSockets/BrowserWebSocket.cs @@ -123,6 +123,7 @@ internal async Task ConnectAsyncJavaScript(Uri uri, CancellationToken cancellati throw new InvalidOperationException(SR.net_WebSockets_AlreadyStarted); } + CancellationTokenRegistration connectRegistration = cancellationToken.Register(cts => ((CancellationTokenSource)cts!).Cancel(), _cts); TaskCompletionSource tcsConnect = new TaskCompletionSource(); // For Abort/Dispose. Calling Abort on the request at any point will close the connection. @@ -164,7 +165,14 @@ internal async Task ConnectAsyncJavaScript(Uri uri, CancellationToken cancellati NativeCleanup(); if ((InternalState)_state == InternalState.Connecting) { - tcsConnect.TrySetException(new WebSocketException(WebSocketError.NativeError)); + if (cancellationToken.IsCancellationRequested) + { + tcsConnect.TrySetCanceled(cancellationToken); + } + else + { + tcsConnect.TrySetException(new WebSocketException(WebSocketError.NativeError)); + } } else { @@ -211,12 +219,20 @@ internal async Task ConnectAsyncJavaScript(Uri uri, CancellationToken cancellati _innerWebSocket.SetObjectProperty("onmessage", _onMessage); await tcsConnect.Task.ConfigureAwait(continueOnCapturedContext: true); } + catch (OperationCanceledException) + { + throw; + } catch (Exception wse) { Dispose(); WebSocketException wex = new WebSocketException(SR.net_webstatus_ConnectFailure, wse); throw wex; } + finally + { + connectRegistration.Unregister(); + } } private void onMessageCallback(JSObject messageEvent) @@ -324,7 +340,7 @@ public override void Dispose() // and called by Dispose or Abort so that any open websocket connection can be closed. private async void AbortRequest() { - if (State == WebSocketState.Open) + if (State == WebSocketState.Open || State == WebSocketState.Connecting) { await CloseAsyncCore(WebSocketCloseStatus.NormalClosure, SR.net_WebSockets_Connection_Aborted, CancellationToken.None).ConfigureAwait(continueOnCapturedContext: true); } @@ -455,7 +471,7 @@ public override async Task CloseAsync(WebSocketCloseStatus closeStatus, string? private async Task CloseAsyncCore(WebSocketCloseStatus closeStatus, string? statusDescription, CancellationToken cancellationToken) { - ThrowOnInvalidState(State, WebSocketState.Open, WebSocketState.CloseReceived, WebSocketState.CloseSent); + ThrowOnInvalidState(State, WebSocketState.Connecting, WebSocketState.Open, WebSocketState.CloseReceived, WebSocketState.CloseSent); WebSocketValidate.ValidateCloseStatus(closeStatus, statusDescription); diff --git a/src/libraries/System.Net.WebSockets.Client/tests/ConnectTest.cs b/src/libraries/System.Net.WebSockets.Client/tests/ConnectTest.cs index 45c94e41644280..75d5ec51b70f2d 100644 --- a/src/libraries/System.Net.WebSockets.Client/tests/ConnectTest.cs +++ b/src/libraries/System.Net.WebSockets.Client/tests/ConnectTest.cs @@ -254,8 +254,8 @@ public async Task ConnectAsync_CancellationRequestedBeforeConnect_ThrowsOperatio using (var clientSocket = new ClientWebSocket()) { var cts = new CancellationTokenSource(); - cts.Cancel(); Task t = clientSocket.ConnectAsync(new Uri("ws://" + Guid.NewGuid().ToString("N")), cts.Token); + cts.Cancel(); await Assert.ThrowsAnyAsync(() => t); } } From 614abd4fa13b2b8501e31449a490fc47c77dd69a Mon Sep 17 00:00:00 2001 From: Kenneth Pouncey Date: Wed, 18 Nov 2020 10:46:01 +0100 Subject: [PATCH 3/8] Add new test for inflight connect - Add new supported property for skipping particular tests when Browser is detected and DOM is detected. --- .../tests/ClientWebSocketTestBase.cs | 2 ++ .../tests/ConnectTest.cs | 13 +++++++++++++ .../tests/WebSocketHelper.cs | 4 ++++ 3 files changed, 19 insertions(+) diff --git a/src/libraries/System.Net.WebSockets.Client/tests/ClientWebSocketTestBase.cs b/src/libraries/System.Net.WebSockets.Client/tests/ClientWebSocketTestBase.cs index ca24740d69cd1e..56b0fa99d8b62a 100644 --- a/src/libraries/System.Net.WebSockets.Client/tests/ClientWebSocketTestBase.cs +++ b/src/libraries/System.Net.WebSockets.Client/tests/ClientWebSocketTestBase.cs @@ -106,5 +106,7 @@ protected static async Task ReceiveEntireMessageAsync(We } public static bool WebSocketsSupported { get { return WebSocketHelper.WebSocketsSupported; } } + // On browser WebSocket is only available when DOM is supported + public static bool WebSocketsSupportedInBrowser { get { return WebSocketHelper.WebSocketsSupportedInBrowser; } } } } diff --git a/src/libraries/System.Net.WebSockets.Client/tests/ConnectTest.cs b/src/libraries/System.Net.WebSockets.Client/tests/ConnectTest.cs index 75d5ec51b70f2d..df9548aab7e257 100644 --- a/src/libraries/System.Net.WebSockets.Client/tests/ConnectTest.cs +++ b/src/libraries/System.Net.WebSockets.Client/tests/ConnectTest.cs @@ -250,6 +250,19 @@ public async Task ConnectAndCloseAsync_UseProxyServer_ExpectedClosedState(Uri se [ConditionalFact(nameof(WebSocketsSupported))] [ActiveIssue("https://github.com/dotnet/runtime/issues/44720", TestPlatforms.Browser)] public async Task ConnectAsync_CancellationRequestedBeforeConnect_ThrowsOperationCanceledException() + { + using (var clientSocket = new ClientWebSocket()) + { + var cts = new CancellationTokenSource(); + cts.Cancel(); + Task t = clientSocket.ConnectAsync(new Uri("ws://" + Guid.NewGuid().ToString("N")), cts.Token); + await Assert.ThrowsAnyAsync(() => t); + } + } + + + [ConditionalFact(nameof(WebSocketsSupported), nameof(WebSocketsSupportedInBrowser))] // On browser the JavaScript host object 'WebSocket' is only available when DOM is supported + public async Task ConnectAsync_CancellationRequestedInflightConnect_ThrowsOperationCanceledException() { using (var clientSocket = new ClientWebSocket()) { diff --git a/src/libraries/System.Net.WebSockets.Client/tests/WebSocketHelper.cs b/src/libraries/System.Net.WebSockets.Client/tests/WebSocketHelper.cs index 110f737ed6e85d..ce3ff58db3cd97 100644 --- a/src/libraries/System.Net.WebSockets.Client/tests/WebSocketHelper.cs +++ b/src/libraries/System.Net.WebSockets.Client/tests/WebSocketHelper.cs @@ -13,6 +13,10 @@ public static class WebSocketHelper { private static readonly Lazy s_WebSocketSupported = new Lazy(InitWebSocketSupported); public static bool WebSocketsSupported { get { return s_WebSocketSupported.Value; } } + // On browser the JavaScript host object 'WebSocket' is only available when DOM is supported + // If DOM is not available then a JavaScript error is thrown + // --- System.Runtime.InteropServices.JavaScript.JSException : JavaScript host object 'WebSocket' not found. + public static bool WebSocketsSupportedInBrowser { get { return !PlatformDetection.IsBrowser || (PlatformDetection.IsBrowser && PlatformDetection.IsBrowserDomSupported); } } public static async Task TestEcho( Uri server, From c7cd30f480f947e8957911cdaff9ccb2158dfcc4 Mon Sep 17 00:00:00 2001 From: Larry Ewing Date: Sun, 22 Nov 2020 18:26:40 -0600 Subject: [PATCH 4/8] first pass at throwing pnse when websocket is missing --- .../BrowserWebSockets/BrowserWebSocket.cs | 26 ++++++++++++++----- .../Net/WebSockets/WebSocketHandle.Browser.cs | 18 ++++++++----- .../tests/ClientWebSocketTestBase.cs | 2 -- .../tests/ConnectTest.cs | 4 +-- .../tests/WebSocketHelper.cs | 5 ---- 5 files changed, 33 insertions(+), 22 deletions(-) diff --git a/src/libraries/System.Net.WebSockets.Client/src/System/Net/WebSockets/BrowserWebSockets/BrowserWebSocket.cs b/src/libraries/System.Net.WebSockets.Client/src/System/Net/WebSockets/BrowserWebSockets/BrowserWebSocket.cs index 0609669c2be47a..af999f12657cc7 100644 --- a/src/libraries/System.Net.WebSockets.Client/src/System/Net/WebSockets/BrowserWebSockets/BrowserWebSocket.cs +++ b/src/libraries/System.Net.WebSockets.Client/src/System/Net/WebSockets/BrowserWebSockets/BrowserWebSocket.cs @@ -59,6 +59,19 @@ private enum InternalState Disposed = 3 } + internal static void ThrowIfPlatformNotSupported() + { + try { + if (JavaScript.Runtime.InvokeJS("typeof (WebSocket)") == "undefined") + { + throw new PlatformNotSupportedException("WebSockets are not supported on this platform"); + } + } + catch (JSException jse) + { + throw new PlatformNotSupportedException("WebSockets are not supported on this platform", jse); + } + } /// /// Initializes a new instance of the class. @@ -219,15 +232,16 @@ internal async Task ConnectAsyncJavaScript(Uri uri, CancellationToken cancellati _innerWebSocket.SetObjectProperty("onmessage", _onMessage); await tcsConnect.Task.ConfigureAwait(continueOnCapturedContext: true); } - catch (OperationCanceledException) - { - throw; - } catch (Exception wse) { Dispose(); - WebSocketException wex = new WebSocketException(SR.net_webstatus_ConnectFailure, wse); - throw wex; + switch (wse) + { + case OperationCanceledException: + throw; + default: + throw new WebSocketException(SR.net_webstatus_ConnectFailure, wse); + } } finally { diff --git a/src/libraries/System.Net.WebSockets.Client/src/System/Net/WebSockets/WebSocketHandle.Browser.cs b/src/libraries/System.Net.WebSockets.Client/src/System/Net/WebSockets/WebSocketHandle.Browser.cs index 0b216531563820..a9338f52136bf2 100644 --- a/src/libraries/System.Net.WebSockets.Client/src/System/Net/WebSockets/WebSocketHandle.Browser.cs +++ b/src/libraries/System.Net.WebSockets.Client/src/System/Net/WebSockets/WebSocketHandle.Browser.cs @@ -14,7 +14,11 @@ internal sealed class WebSocketHandle public WebSocket? WebSocket { get; private set; } public WebSocketState State => WebSocket?.State ?? _state; - public static ClientWebSocketOptions CreateDefaultOptions() => new ClientWebSocketOptions(); + public static ClientWebSocketOptions CreateDefaultOptions() + { + BrowserWebSocket.ThrowIfPlatformNotSupported(); + return new ClientWebSocketOptions(); + } public void Dispose() { @@ -62,12 +66,14 @@ public async Task ConnectAsync(Uri uri, CancellationToken cancellationToken, Cli Abort(); - if (exc is WebSocketException || - (exc is OperationCanceledException && cancellationToken.IsCancellationRequested)) - { - throw; + switch (exc) { + case WebSocketException: + case PlatformNotSupportedException: + case OperationCanceledException _ when cancellationToken.IsCancellationRequested: + throw; + default: + throw new WebSocketException(SR.net_webstatus_ConnectFailure, exc); } - throw new WebSocketException(SR.net_webstatus_ConnectFailure, exc); } } } diff --git a/src/libraries/System.Net.WebSockets.Client/tests/ClientWebSocketTestBase.cs b/src/libraries/System.Net.WebSockets.Client/tests/ClientWebSocketTestBase.cs index 56b0fa99d8b62a..ca24740d69cd1e 100644 --- a/src/libraries/System.Net.WebSockets.Client/tests/ClientWebSocketTestBase.cs +++ b/src/libraries/System.Net.WebSockets.Client/tests/ClientWebSocketTestBase.cs @@ -106,7 +106,5 @@ protected static async Task ReceiveEntireMessageAsync(We } public static bool WebSocketsSupported { get { return WebSocketHelper.WebSocketsSupported; } } - // On browser WebSocket is only available when DOM is supported - public static bool WebSocketsSupportedInBrowser { get { return WebSocketHelper.WebSocketsSupportedInBrowser; } } } } diff --git a/src/libraries/System.Net.WebSockets.Client/tests/ConnectTest.cs b/src/libraries/System.Net.WebSockets.Client/tests/ConnectTest.cs index df9548aab7e257..24bfbc26c44aa1 100644 --- a/src/libraries/System.Net.WebSockets.Client/tests/ConnectTest.cs +++ b/src/libraries/System.Net.WebSockets.Client/tests/ConnectTest.cs @@ -248,7 +248,6 @@ public async Task ConnectAndCloseAsync_UseProxyServer_ExpectedClosedState(Uri se } [ConditionalFact(nameof(WebSocketsSupported))] - [ActiveIssue("https://github.com/dotnet/runtime/issues/44720", TestPlatforms.Browser)] public async Task ConnectAsync_CancellationRequestedBeforeConnect_ThrowsOperationCanceledException() { using (var clientSocket = new ClientWebSocket()) @@ -260,8 +259,7 @@ public async Task ConnectAsync_CancellationRequestedBeforeConnect_ThrowsOperatio } } - - [ConditionalFact(nameof(WebSocketsSupported), nameof(WebSocketsSupportedInBrowser))] // On browser the JavaScript host object 'WebSocket' is only available when DOM is supported + [ConditionalFact(nameof(WebSocketsSupported))] public async Task ConnectAsync_CancellationRequestedInflightConnect_ThrowsOperationCanceledException() { using (var clientSocket = new ClientWebSocket()) diff --git a/src/libraries/System.Net.WebSockets.Client/tests/WebSocketHelper.cs b/src/libraries/System.Net.WebSockets.Client/tests/WebSocketHelper.cs index ce3ff58db3cd97..d0f39d942b3c59 100644 --- a/src/libraries/System.Net.WebSockets.Client/tests/WebSocketHelper.cs +++ b/src/libraries/System.Net.WebSockets.Client/tests/WebSocketHelper.cs @@ -13,11 +13,6 @@ public static class WebSocketHelper { private static readonly Lazy s_WebSocketSupported = new Lazy(InitWebSocketSupported); public static bool WebSocketsSupported { get { return s_WebSocketSupported.Value; } } - // On browser the JavaScript host object 'WebSocket' is only available when DOM is supported - // If DOM is not available then a JavaScript error is thrown - // --- System.Runtime.InteropServices.JavaScript.JSException : JavaScript host object 'WebSocket' not found. - public static bool WebSocketsSupportedInBrowser { get { return !PlatformDetection.IsBrowser || (PlatformDetection.IsBrowser && PlatformDetection.IsBrowserDomSupported); } } - public static async Task TestEcho( Uri server, WebSocketMessageType type, From bf374e594ea8b5b4e3c5a7fd848cedaa420898c6 Mon Sep 17 00:00:00 2001 From: Kenneth Pouncey Date: Mon, 7 Dec 2020 14:11:03 +0100 Subject: [PATCH 5/8] Address review comment --- .../System.Net.WebSockets.Client/tests/WebSocketHelper.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libraries/System.Net.WebSockets.Client/tests/WebSocketHelper.cs b/src/libraries/System.Net.WebSockets.Client/tests/WebSocketHelper.cs index d0f39d942b3c59..110f737ed6e85d 100644 --- a/src/libraries/System.Net.WebSockets.Client/tests/WebSocketHelper.cs +++ b/src/libraries/System.Net.WebSockets.Client/tests/WebSocketHelper.cs @@ -13,6 +13,7 @@ public static class WebSocketHelper { private static readonly Lazy s_WebSocketSupported = new Lazy(InitWebSocketSupported); public static bool WebSocketsSupported { get { return s_WebSocketSupported.Value; } } + public static async Task TestEcho( Uri server, WebSocketMessageType type, From 455ab54f566096aa4616743d217763b07168ec38 Mon Sep 17 00:00:00 2001 From: Larry Ewing Date: Mon, 7 Dec 2020 10:46:59 -0600 Subject: [PATCH 6/8] Make the platform check explicit --- .../BrowserWebSockets/BrowserWebSocket.cs | 13 ------------- .../Net/WebSockets/WebSocketHandle.Browser.cs | 1 - .../tests/WebSocketHelper.cs | 5 +++++ 3 files changed, 5 insertions(+), 14 deletions(-) diff --git a/src/libraries/System.Net.WebSockets.Client/src/System/Net/WebSockets/BrowserWebSockets/BrowserWebSocket.cs b/src/libraries/System.Net.WebSockets.Client/src/System/Net/WebSockets/BrowserWebSockets/BrowserWebSocket.cs index af999f12657cc7..25cecaf3e3d9d6 100644 --- a/src/libraries/System.Net.WebSockets.Client/src/System/Net/WebSockets/BrowserWebSockets/BrowserWebSocket.cs +++ b/src/libraries/System.Net.WebSockets.Client/src/System/Net/WebSockets/BrowserWebSockets/BrowserWebSocket.cs @@ -59,19 +59,6 @@ private enum InternalState Disposed = 3 } - internal static void ThrowIfPlatformNotSupported() - { - try { - if (JavaScript.Runtime.InvokeJS("typeof (WebSocket)") == "undefined") - { - throw new PlatformNotSupportedException("WebSockets are not supported on this platform"); - } - } - catch (JSException jse) - { - throw new PlatformNotSupportedException("WebSockets are not supported on this platform", jse); - } - } /// /// Initializes a new instance of the class. diff --git a/src/libraries/System.Net.WebSockets.Client/src/System/Net/WebSockets/WebSocketHandle.Browser.cs b/src/libraries/System.Net.WebSockets.Client/src/System/Net/WebSockets/WebSocketHandle.Browser.cs index a9338f52136bf2..6a8a9bf4a9b964 100644 --- a/src/libraries/System.Net.WebSockets.Client/src/System/Net/WebSockets/WebSocketHandle.Browser.cs +++ b/src/libraries/System.Net.WebSockets.Client/src/System/Net/WebSockets/WebSocketHandle.Browser.cs @@ -16,7 +16,6 @@ internal sealed class WebSocketHandle public static ClientWebSocketOptions CreateDefaultOptions() { - BrowserWebSocket.ThrowIfPlatformNotSupported(); return new ClientWebSocketOptions(); } diff --git a/src/libraries/System.Net.WebSockets.Client/tests/WebSocketHelper.cs b/src/libraries/System.Net.WebSockets.Client/tests/WebSocketHelper.cs index 110f737ed6e85d..1f0ccd55913214 100644 --- a/src/libraries/System.Net.WebSockets.Client/tests/WebSocketHelper.cs +++ b/src/libraries/System.Net.WebSockets.Client/tests/WebSocketHelper.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Net.Test.Common; using System.Threading; using System.Threading.Tasks; @@ -124,6 +125,10 @@ public static async Task Retry(ITestOutputHelper output, Func> fun private static bool InitWebSocketSupported() { ClientWebSocket cws = null; + if (PlatformDetection.IsBrowser && !PlatformDetection.IsBrowserDomSupported) + { + return false; + } try { From 3d64d1014f9926ad349464f79a05583d2c602b7e Mon Sep 17 00:00:00 2001 From: Larry Ewing Date: Mon, 7 Dec 2020 11:32:16 -0600 Subject: [PATCH 7/8] Revert CreateDefaultOptions change --- .../src/System/Net/WebSockets/WebSocketHandle.Browser.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/libraries/System.Net.WebSockets.Client/src/System/Net/WebSockets/WebSocketHandle.Browser.cs b/src/libraries/System.Net.WebSockets.Client/src/System/Net/WebSockets/WebSocketHandle.Browser.cs index 6a8a9bf4a9b964..60548d5a0acca4 100644 --- a/src/libraries/System.Net.WebSockets.Client/src/System/Net/WebSockets/WebSocketHandle.Browser.cs +++ b/src/libraries/System.Net.WebSockets.Client/src/System/Net/WebSockets/WebSocketHandle.Browser.cs @@ -14,10 +14,7 @@ internal sealed class WebSocketHandle public WebSocket? WebSocket { get; private set; } public WebSocketState State => WebSocket?.State ?? _state; - public static ClientWebSocketOptions CreateDefaultOptions() - { - return new ClientWebSocketOptions(); - } + public static ClientWebSocketOptions CreateDefaultOptions() => new ClientWebSocketOptions(); public void Dispose() { From 6e7c297b7aa9a29cf818d4cd9929b756c72b6bdc Mon Sep 17 00:00:00 2001 From: Kenneth Pouncey Date: Tue, 8 Dec 2020 11:13:03 +0100 Subject: [PATCH 8/8] Address review comment --- .../src/System/Net/WebSockets/WebSocketHandle.Browser.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libraries/System.Net.WebSockets.Client/src/System/Net/WebSockets/WebSocketHandle.Browser.cs b/src/libraries/System.Net.WebSockets.Client/src/System/Net/WebSockets/WebSocketHandle.Browser.cs index 60548d5a0acca4..cf91e6821db05e 100644 --- a/src/libraries/System.Net.WebSockets.Client/src/System/Net/WebSockets/WebSocketHandle.Browser.cs +++ b/src/libraries/System.Net.WebSockets.Client/src/System/Net/WebSockets/WebSocketHandle.Browser.cs @@ -64,7 +64,6 @@ public async Task ConnectAsync(Uri uri, CancellationToken cancellationToken, Cli switch (exc) { case WebSocketException: - case PlatformNotSupportedException: case OperationCanceledException _ when cancellationToken.IsCancellationRequested: throw; default: