Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unhandled exception crashes Web API service when thrown in async void action

According to documentation HttpResponseException are handled by Web API automatically and Web API should just return HttpResponseMessage to client with corresponding HttpStatusCode. And it works... usually.

But if we throw HttpResponseException from an action marked with async then this just doesn't work and HttpResponseException just crashes the whole service with something like "Exception has been unhandled by user code" message. Adding custom exception filter doesn't solve the problem as Web API doesn't catch HttpResponseException message.

Update 1 I've investigated further and have found out that as soon as you add await modifier to an action, then every unhandled exception from this action crashes Web API service. And no ExceptionFilterAttributes are involved, Web API just doesn't execute them. You even don't have to thrown exception from really asynchronous code, it is enough to add async to action to cause every exception be totally unhandled.

Here, this works ok, the exception can be caught by some exception filter:

public void Test()
{
    throw new Exception("Hello");
}

And this causes service to crash:

public async void Test()
{
    throw new Exception("Hello");
}

Update 2 Well, looks like everything works fine if we change void to some real type, here:

public async Task<int> Test()
{
    throw new Exception("Hello");
}

So, looks like unhandled exception from async void cause service to crash, but async Task<SomeType> works well, exception filters catch everything except HttpResponseException and HttpResponseException is correctly handled by Web API.

Looks like I've just talked to myself, but it would be interesting to find out why exceptions in async void actions can't be handled correctly?

like image 536
Dmitrii Lobanov Avatar asked Oct 05 '22 00:10

Dmitrii Lobanov


1 Answers

One of the reasons to avoid async void is the way those methods do error handling.

async void methods are intended to be used as event handlers. All other async methods should be async Task or async Task<T>. The async equivalent of a synchronous void-returning method is async Task, not async void.

async methods returning a task object will place the exception on that task object. async void methods do not have a task object, so they handle exceptions by raising them on the SynchronizationContext that was active at the time the async void method started executing. This emulates the behavior of event handlers.

like image 58
Stephen Cleary Avatar answered Oct 10 '22 04:10

Stephen Cleary