Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Catch an exception thrown by an async void method

Using the async CTP from Microsoft for .NET, is it possible to catch an exception thrown by an async method in the calling method?

public async void Foo() {     var x = await DoSomethingAsync();      /* Handle the result, but sometimes an exception might be thrown.        For example, DoSomethingAsync gets data from the network        and the data is invalid... a ProtocolException might be thrown. */ }  public void DoFoo() {     try     {         Foo();     }     catch (ProtocolException ex)     {           /* The exception will never be caught.              Instead when in debug mode, VS2010 will warn and continue.              The deployed the app will simply crash. */     } } 

So basically I want the exception from the async code to bubble up into my calling code if that is even possible at all.

like image 823
TimothyP Avatar asked Mar 21 '11 20:03

TimothyP


People also ask

What happens if an exception is thrown within an asynchronous method?

Async void methods have different error-handling semantics. When an exception is thrown out of an async Task or async Task method, that exception is captured and placed on the Task object.

How do I get async exception?

To catch an exception that an async task throws, place the await expression in a try block, and catch the exception in a catch block. Uncomment the throw new Exception line in the example to demonstrate exception handling. The task's IsFaulted property is set to True , the task's Exception.

Can we use async with void?

Async Task methods enable easier error-handling, composability and testability. The exception to this guideline is asynchronous event handlers, which must return void. This exception includes methods that are logically event handlers even if they're not literally event handlers (for example, ICommand.

Are exceptions handled asynchronously?

Learn the exception handling semantics for asynchronous methods in C# Exception handling is the technique of handling runtime errors in an application. Asynchronous programming allows us to perform resource-intensive operations without the need for blocking on the main or executing thread of the application.


2 Answers

It's somewhat weird to read but yes, the exception will bubble up to the calling code - but only if you await or Wait() the call to Foo.

public async Task Foo() {     var x = await DoSomethingAsync(); }  public async void DoFoo() {     try     {         await Foo();     }     catch (ProtocolException ex)     {           // The exception will be caught because you've awaited           // the call in an async method.     } }  //or//  public void DoFoo() {     try     {         Foo().Wait();     }     catch (ProtocolException ex)     {           /* The exception will be caught because you've              waited for the completion of the call. */     } }  

As Stephen Cleary wrote in Async/Await - Best Practices in Asynchronous Programming:

Async void methods have different error-handling semantics. When an exception is thrown out of an async Task or async Task method, that exception is captured and placed on the Task object. With async void methods, there is no Task object, so any exceptions thrown out of an async void method will be raised directly on the SynchronizationContext that was active when the async void method started.

Note that using Wait() may cause your application to block, if .NET decides to execute your method synchronously.

This explanation http://www.interact-sw.co.uk/iangblog/2010/11/01/csharp5-async-exceptions is pretty good - it discusses the steps the compiler takes to achieve this magic.

like image 186
Stuart Avatar answered Oct 06 '22 01:10

Stuart


The reason the exception is not caught is because the Foo() method has a void return type and so when await is called, it simply returns. As DoFoo() is not awaiting the completion of Foo, the exception handler cannot be used.

This opens up a simpler solution if you can change the method signatures - alter Foo() so that it returns type Task and then DoFoo() can await Foo(), as in this code:

public async Task Foo() {     var x = await DoSomethingThatThrows(); }  public async void DoFoo() {     try {         await Foo();     } catch (ProtocolException ex) {         // This will catch exceptions from DoSomethingThatThrows     } } 
like image 37
Rob Church Avatar answered Oct 06 '22 02:10

Rob Church