Skip to content

Commit

Permalink
Minor changes related to ConfigureAwait(false).
Browse files Browse the repository at this point in the history
  • Loading branch information
yallie committed Dec 9, 2024
1 parent 2552117 commit 87eaa96
Show file tree
Hide file tree
Showing 9 changed files with 136 additions and 59 deletions.
1 change: 1 addition & 0 deletions CoreRemoting.Tests/CoreRemoting.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
<!-- Exclude the unnecessary tests to save Github Actions time -->
<!-- WatsonTcp is the default channel, WebSocketSharp is optional -->
<ItemGroup>
<Compile Remove="DisposableTests.Async.cs" />
<Compile Remove="RpcTests_WatsonTcp.cs" />
<Compile Remove="RpcTests_WebsocketSharp.cs" />
<Compile Remove="RpcTests_WsClientWsharpServer.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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()
{
Expand Down
52 changes: 52 additions & 0 deletions CoreRemoting.Tests/DisposableTests.Sync.cs
Original file line number Diff line number Diff line change
@@ -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);
}
}
}
38 changes: 23 additions & 15 deletions CoreRemoting/Channels/Websocket/WebsocketClientChannel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public class WebsocketClientChannel : IClientChannel, IRawMessageTransport
{
// note: LOH threshold is ~85 kilobytes
private const int BufferSize = 16 * 1024;
private static ArraySegment<byte> EmptyMessage = new ArraySegment<byte>([]);

/// <summary>
/// Gets or sets the URL this channel is connected to.
Expand Down Expand Up @@ -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<byte>(Array.Empty<byte>()), 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; }
Expand All @@ -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();
}
Expand Down Expand Up @@ -160,10 +167,9 @@ public bool SendMessage(byte[] rawMessage)
try
{
var segment = new ArraySegment<byte>(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;
}
Expand All @@ -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();
});
Expand All @@ -201,8 +210,7 @@ public void Dispose()

var task = DisconnectTask;
if (task != null)
task.ConfigureAwait(false)
.GetAwaiter()
task.GetAwaiter()
.GetResult();

WebSocket.Dispose();
Expand Down
8 changes: 6 additions & 2 deletions CoreRemoting/Channels/Websocket/WebsocketServerChannel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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(),
Expand Down
19 changes: 9 additions & 10 deletions CoreRemoting/Channels/Websocket/WebsocketServerConnection.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System;
using System.Net;
using System.Net.WebSockets;
using System.Threading;
using System.Threading.Tasks;
Expand Down Expand Up @@ -56,10 +55,9 @@ public bool SendMessage(byte[] rawMessage)
try
{
var segment = new ArraySegment<byte>(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;
}
Expand Down Expand Up @@ -109,20 +107,21 @@ private async Task ReadIncomingMessages()
{
var buffer = new byte[BufferSize];
var segment = new ArraySegment<byte>(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();
Expand All @@ -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);
}
}
}
Expand All @@ -156,7 +155,7 @@ await WebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure,
}
finally
{
WebSocket?.Dispose();
webSocket?.Dispose();
}
}
}
4 changes: 4 additions & 0 deletions CoreRemoting/CoreRemoting.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -61,5 +61,9 @@
<ItemGroup>
<Protobuf Include="**/*.proto" />
</ItemGroup>

<ItemGroup>
<Compile Remove="Toolbox\Disposable.Async.cs" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,8 @@

namespace CoreRemoting.Toolbox
{
/// <summary>
/// Helper class to create disposable primitives.
/// </summary>
public static class Disposable
static partial class Disposable
{
private class SyncDisposable(Action disposeAction) : IDisposable
{
void IDisposable.Dispose() =>
disposeAction?.Invoke();
}

/// <summary>
/// Creates a disposable object.
/// </summary>
/// <param name="disposeAction">An action to invoke on disposal.</param>
public static IDisposable Create(Action disposeAction) =>
new SyncDisposable(disposeAction);

private class AsyncDisposable(
Func<ValueTask> disposeAsync,
Func<Task> disposeTaskAsync) : IAsyncDisposable
Expand Down
39 changes: 39 additions & 0 deletions CoreRemoting/Toolbox/Disposable.Sync.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using System;

namespace CoreRemoting.Toolbox
{
/// <summary>
/// Helper class to create disposable primitives.
/// </summary>
public static partial class Disposable
{
private class SyncDisposable(Action disposeAction) : IDisposable
{
void IDisposable.Dispose() =>
disposeAction?.Invoke();
}

/// <summary>
/// Creates a disposable object.
/// </summary>
/// <param name="disposeAction">An action to invoke on disposal.</param>
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();
}
}

/// <summary>
/// Creates a disposable object.
/// </summary>
/// <param name="disposables">Disposable items to dispose on disposal.</param>
public static IDisposable Create(params IDisposable[] disposables) =>
new ParamsDisposable(disposables);
}
}

0 comments on commit 87eaa96

Please sign in to comment.