Exception handling and async void methods
TL;DR #
async void
methods should be avoided:
- They do not allow error propagation outside of them.
- They cannot be awaited unlike
async Task
, which might cause concurrency issues. - Use try/catch inside the
async void
or replace it with an awaitedasync Task
method.
Issue #
Say you have a method definition that expects an Action
delegate.
Task ReceiveMessageAsync(WebSocket socket, Action<WebSocketReceiveResult, byte[]> handleMessage);
Action
delegates are used to pass event handlers that have no return type to other methods.
Then you try and handle the error coming from the Action
(async void
method) as such:
try
{
await _manager.ReceiveMessageAsync(_webSocket, HandleMessage);
}
catch (ConnectionAbortedException ex)
{
}
The exception does not get handled and crashes the application.
async void
methods are not designed to do this. However, async Task
methods are.
Solutions #
Pass a Func
delegate to a function. However now you have to make sure it’s also awaited inside the method.
Method signature changes to this:
public Task ReceiveMessageAsync(WebSocket socket, Task<WebSocketReceiveResult, byte[], Task> handleMessage)
{
// Receive message
await handleMessage(result, buf);
}
Of course, it’s not ideal inside a method that receives messages. This could cause some lag between messages, as it would be handling a message and delaying other messages.
If it’s really neccesary wrap the code in the method with a try/catch block:
private async void HandleMessage(WebSocketReceiveResult result, byte[] buf)
{
try
{
// Handle message
}
catch (ConnectionAbortedException ex)
{
}
}
Hope this helps, as it caused me some pain understanding why the error was not getting propagated. 😄
Read More: