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?
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With