From 87eaa96e44c79d4574d2f9b7a58047cbfb10fdfa Mon Sep 17 00:00:00 2001 From: yallie Date: Mon, 9 Dec 2024 20:48:29 +0300 Subject: [PATCH] Minor changes related to ConfigureAwait(false). --- CoreRemoting.Tests/CoreRemoting.Tests.csproj | 1 + ...sableTests.cs => DisposableTests.Async.cs} | 16 +----- CoreRemoting.Tests/DisposableTests.Sync.cs | 52 +++++++++++++++++++ .../Websocket/WebsocketClientChannel.cs | 38 ++++++++------ .../Websocket/WebsocketServerChannel.cs | 8 ++- .../Websocket/WebsocketServerConnection.cs | 19 ++++--- CoreRemoting/CoreRemoting.csproj | 4 ++ .../{Disposable.cs => Disposable.Async.cs} | 18 +------ CoreRemoting/Toolbox/Disposable.Sync.cs | 39 ++++++++++++++ 9 files changed, 136 insertions(+), 59 deletions(-) rename CoreRemoting.Tests/{DisposableTests.cs => DisposableTests.Async.cs} (73%) create mode 100644 CoreRemoting.Tests/DisposableTests.Sync.cs rename CoreRemoting/Toolbox/{Disposable.cs => Disposable.Async.cs} (66%) create mode 100644 CoreRemoting/Toolbox/Disposable.Sync.cs diff --git a/CoreRemoting.Tests/CoreRemoting.Tests.csproj b/CoreRemoting.Tests/CoreRemoting.Tests.csproj index 39ae35d..e977889 100644 --- a/CoreRemoting.Tests/CoreRemoting.Tests.csproj +++ b/CoreRemoting.Tests/CoreRemoting.Tests.csproj @@ -9,6 +9,7 @@ + diff --git a/CoreRemoting.Tests/DisposableTests.cs b/CoreRemoting.Tests/DisposableTests.Async.cs similarity index 73% rename from CoreRemoting.Tests/DisposableTests.cs rename to CoreRemoting.Tests/DisposableTests.Async.cs index df339ba..7215daa 100644 --- a/CoreRemoting.Tests/DisposableTests.cs +++ b/CoreRemoting.Tests/DisposableTests.Async.cs @@ -4,22 +4,8 @@ namespace CoreRemoting.Tests { - public class DisposableTests + partial class DisposableTests { - [Fact] - public void Disposable_executes_action_on_Dispose() - { - var disposed = false; - - void Dispose() => - disposed = true; - - using (Disposable.Create(Dispose)) - Assert.False(disposed); - - Assert.True(disposed); - } - [Fact] public async Task AsyncDisposable_executes_action_on_DisposeAsync() { diff --git a/CoreRemoting.Tests/DisposableTests.Sync.cs b/CoreRemoting.Tests/DisposableTests.Sync.cs new file mode 100644 index 0000000..38a32ae --- /dev/null +++ b/CoreRemoting.Tests/DisposableTests.Sync.cs @@ -0,0 +1,52 @@ +using CoreRemoting.Toolbox; +using System; +using System.Threading.Tasks; +using Xunit; + +namespace CoreRemoting.Tests +{ + public partial class DisposableTests + { + [Fact] + public void Disposable_executes_action_on_Dispose() + { + var disposed = false; + + void Dispose() => + disposed = true; + + using (Disposable.Create(Dispose)) + Assert.False(disposed); + + Assert.True(disposed); + } + + [Fact] + public void Disposable_ignores_nulls() + { + Action dispose = null; + + using (Disposable.Create(dispose)) + { + // doesn't throw + } + } + + [Fact] + public void Disposable_combines_disposables() + { + var count = 0; + void Dispose() => + count++; + + var d1 = Disposable.Create(Dispose); + var d2 = Disposable.Create(Dispose); + var d3 = Disposable.Create(Dispose); + + using (Disposable.Create(d1, d2, d3)) + Assert.Equal(0, count); + + Assert.Equal(3, count); + } + } +} \ No newline at end of file diff --git a/CoreRemoting/Channels/Websocket/WebsocketClientChannel.cs b/CoreRemoting/Channels/Websocket/WebsocketClientChannel.cs index 01de49f..5bf1504 100644 --- a/CoreRemoting/Channels/Websocket/WebsocketClientChannel.cs +++ b/CoreRemoting/Channels/Websocket/WebsocketClientChannel.cs @@ -14,6 +14,7 @@ public class WebsocketClientChannel : IClientChannel, IRawMessageTransport { // note: LOH threshold is ~85 kilobytes private const int BufferSize = 16 * 1024; + private static ArraySegment EmptyMessage = new ArraySegment([]); /// /// Gets or sets the URL this channel is connected to. @@ -83,17 +84,21 @@ public void Connect() { ConnectTask = ConnectTask ?? Task.Factory.StartNew(async () => { - await WebSocket.ConnectAsync(new Uri(Url), CancellationToken.None); + await WebSocket.ConnectAsync( + new Uri(Url), CancellationToken.None) + .ConfigureAwait(false); + IsConnected = true; Connected?.Invoke(); - await WebSocket.SendAsync(new ArraySegment(Array.Empty()), WebSocketMessageType.Binary, true, CancellationToken.None); + await WebSocket.SendAsync(EmptyMessage, + WebSocketMessageType.Binary, true, CancellationToken.None) + .ConfigureAwait(false); + _ = StartListening(); }); - ConnectTask.ConfigureAwait(false) - .GetAwaiter() - .GetResult(); + ConnectTask.GetAwaiter().GetResult(); } private Task ConnectTask { get; set; } @@ -111,13 +116,15 @@ private async Task StartListening() var ms = new SmallBlockMemoryStream(); while (true) { - var result = await webSocket.ReceiveAsync(segment, - CancellationToken.None).ConfigureAwait(false); + var result = await webSocket.ReceiveAsync( + segment, CancellationToken.None) + .ConfigureAwait(false); if (result.MessageType == WebSocketMessageType.Close) { await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, - string.Empty, CancellationToken.None).ConfigureAwait(false); + string.Empty, CancellationToken.None) + .ConfigureAwait(false); Disconnected?.Invoke(); } @@ -160,10 +167,9 @@ public bool SendMessage(byte[] rawMessage) try { var segment = new ArraySegment(rawMessage); - WebSocket.SendAsync(segment, WebSocketMessageType.Binary, true, CancellationToken.None) - .ConfigureAwait(false) - .GetAwaiter() - .GetResult(); + WebSocket.SendAsync(segment, + WebSocketMessageType.Binary, true, CancellationToken.None) + .GetAwaiter().GetResult(); return true; } @@ -184,7 +190,10 @@ public void Disconnect() { DisconnectTask = DisconnectTask ?? Task.Factory.StartNew(async () => { - await WebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Ok", CancellationToken.None); + await WebSocket.CloseAsync( + WebSocketCloseStatus.NormalClosure, "Ok", CancellationToken.None) + .ConfigureAwait(false); + IsConnected = false; Disconnected?.Invoke(); }); @@ -201,8 +210,7 @@ public void Dispose() var task = DisconnectTask; if (task != null) - task.ConfigureAwait(false) - .GetAwaiter() + task.GetAwaiter() .GetResult(); WebSocket.Dispose(); diff --git a/CoreRemoting/Channels/Websocket/WebsocketServerChannel.cs b/CoreRemoting/Channels/Websocket/WebsocketServerChannel.cs index f39ecf2..3a0dbdd 100644 --- a/CoreRemoting/Channels/Websocket/WebsocketServerChannel.cs +++ b/CoreRemoting/Channels/Websocket/WebsocketServerChannel.cs @@ -46,7 +46,9 @@ public void StartListening() private async Task ReceiveConnection() { // check if it's a websocket request - var context = await HttpListener.GetContextAsync(); + var context = await HttpListener.GetContextAsync() + .ConfigureAwait(false); + if (!context.Request.IsWebSocketRequest) { context.Response.StatusCode = (int)HttpStatusCode.BadRequest; @@ -55,7 +57,9 @@ private async Task ReceiveConnection() } // accept websocket request and start a new session - var websocketContext = await context.AcceptWebSocketAsync(null); + var websocketContext = await context.AcceptWebSocketAsync(null) + .ConfigureAwait(false); + var websocket = websocketContext.WebSocket; var connection = new WebsocketServerConnection( context.Request.RemoteEndPoint.ToString(), diff --git a/CoreRemoting/Channels/Websocket/WebsocketServerConnection.cs b/CoreRemoting/Channels/Websocket/WebsocketServerConnection.cs index f65a302..d805ee8 100644 --- a/CoreRemoting/Channels/Websocket/WebsocketServerConnection.cs +++ b/CoreRemoting/Channels/Websocket/WebsocketServerConnection.cs @@ -1,5 +1,4 @@ using System; -using System.Net; using System.Net.WebSockets; using System.Threading; using System.Threading.Tasks; @@ -56,10 +55,9 @@ public bool SendMessage(byte[] rawMessage) try { var segment = new ArraySegment(rawMessage); - WebSocket.SendAsync(segment, WebSocketMessageType.Binary, true, CancellationToken.None) - .ConfigureAwait(false) - .GetAwaiter() - .GetResult(); + WebSocket.SendAsync(segment, + WebSocketMessageType.Binary, true, CancellationToken.None) + .GetAwaiter().GetResult(); return true; } @@ -109,20 +107,21 @@ private async Task ReadIncomingMessages() { var buffer = new byte[BufferSize]; var segment = new ArraySegment(buffer); + var webSocket = WebSocket; try { - while (WebSocket.State == WebSocketState.Open) + while (webSocket.State == WebSocketState.Open) { var ms = new SmallBlockMemoryStream(); while (true) { - var result = await WebSocket.ReceiveAsync(segment, + var result = await webSocket.ReceiveAsync(segment, CancellationToken.None).ConfigureAwait(false); if (result.MessageType == WebSocketMessageType.Close) { - await WebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, + await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None).ConfigureAwait(false); Disconnected?.Invoke(); @@ -142,7 +141,7 @@ await WebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, var message = new byte[(int)ms.Length]; ms.Position = 0; ms.Read(message, 0, message.Length); - ReceiveMessage(message); + ReceiveMessage?.Invoke(message); } } } @@ -156,7 +155,7 @@ await WebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, } finally { - WebSocket?.Dispose(); + webSocket?.Dispose(); } } } diff --git a/CoreRemoting/CoreRemoting.csproj b/CoreRemoting/CoreRemoting.csproj index 0776e0f..2a68025 100644 --- a/CoreRemoting/CoreRemoting.csproj +++ b/CoreRemoting/CoreRemoting.csproj @@ -61,5 +61,9 @@ + + + + diff --git a/CoreRemoting/Toolbox/Disposable.cs b/CoreRemoting/Toolbox/Disposable.Async.cs similarity index 66% rename from CoreRemoting/Toolbox/Disposable.cs rename to CoreRemoting/Toolbox/Disposable.Async.cs index 44933f0..f040435 100644 --- a/CoreRemoting/Toolbox/Disposable.cs +++ b/CoreRemoting/Toolbox/Disposable.Async.cs @@ -3,24 +3,8 @@ namespace CoreRemoting.Toolbox { - /// - /// Helper class to create disposable primitives. - /// - public static class Disposable + static partial class Disposable { - private class SyncDisposable(Action disposeAction) : IDisposable - { - void IDisposable.Dispose() => - disposeAction?.Invoke(); - } - - /// - /// Creates a disposable object. - /// - /// An action to invoke on disposal. - public static IDisposable Create(Action disposeAction) => - new SyncDisposable(disposeAction); - private class AsyncDisposable( Func disposeAsync, Func disposeTaskAsync) : IAsyncDisposable diff --git a/CoreRemoting/Toolbox/Disposable.Sync.cs b/CoreRemoting/Toolbox/Disposable.Sync.cs new file mode 100644 index 0000000..89b5c0f --- /dev/null +++ b/CoreRemoting/Toolbox/Disposable.Sync.cs @@ -0,0 +1,39 @@ +using System; + +namespace CoreRemoting.Toolbox +{ + /// + /// Helper class to create disposable primitives. + /// + public static partial class Disposable + { + private class SyncDisposable(Action disposeAction) : IDisposable + { + void IDisposable.Dispose() => + disposeAction?.Invoke(); + } + + /// + /// Creates a disposable object. + /// + /// An action to invoke on disposal. + public static IDisposable Create(Action disposeAction) => + new SyncDisposable(disposeAction); + + private class ParamsDisposable(params IDisposable[] disposables) : IDisposable + { + void IDisposable.Dispose() + { + foreach (var disposable in disposables ?? []) + disposable?.Dispose(); + } + } + + /// + /// Creates a disposable object. + /// + /// Disposable items to dispose on disposal. + public static IDisposable Create(params IDisposable[] disposables) => + new ParamsDisposable(disposables); + } +}