Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unobserved Task exceptions in .NET 4.5 still crash app

Tags:

c#

.net

In Steven Toub's article:

To make it easier for developers to write asynchronous code based on Tasks, .NET 4.5 changes the default exception behavior for unobserved exceptions. While unobserved exceptions will still cause the UnobservedTaskException event to be raised (not doing so would be a breaking change), the process will not crash by default. Rather, the exception will end up getting eaten after the event is raised, regardless of whether an event handler observes the exception.

But the result of my experiment does not match the above statement. Below is my code:

static void Main(string[] args)
{
    DownloadAsync("http://an.invalid.url.com);
}

async static void DownloadAsync(string url)
{
    using (var client = new System.Net.Http.HttpClient())
    {
        string text = await client.GetStringAsync(url);
        Console.WriteLine("Downloaded {0} chars", text.Length);
    }
}

Since I pass an invalid url to DownloadAsync() method, the call to HttpClient's GetStringAsync() method will throw an expcetion, and it crashes the application.

So my question is: Does unobserved exceptions in .NET 4.5 still crash app by default?

like image 904
Michael Tsai Avatar asked Apr 18 '13 22:04

Michael Tsai


People also ask

What is unobserved task exception?

An “unobserved” exception is one that's stored into the task but then never looked at in any way by the consuming code. There are many ways of observing the exception, including Wait()'ing on the Task, accessing a Task<TResult>'s Result, looking at the Task's Exception property, and so on.

How do you handle exceptions thrown by tasks?

You can also handle the original exceptions by using the AggregateException. Handle method. Even if only one exception is thrown, it is still wrapped in an AggregateException exception, as the following example shows. public static partial class Program { public static void HandleThree() { var task = Task.

What happens when a task throws an exception C#?

When an exception occurs in an async method that has a return type of Task or Task<TResult>, the exception object is wrapped in an instance of AggregateException and attached to the Task object. If multiple exceptions are thrown, all of them are stored in the Task object.


1 Answers

You do have a Task with an exception (the one returned by GetStringAsync). However, the await is observing the Task exception, which then propagates out of the DownloadAsync method (which is async void).

Exceptions propagating out of async void methods behave differently; they are raised on the SynchronizationContext that was active when the async void method started (in this case, a thread pool SynchronizationContext). This is not considered an unobserved exception.

If you change DownloadAsync to return Task, then you will have an actual unobserved Task exception, which will be ignored (correctly):

static void Main(string[] args)
{
  DownloadAsync("http://an.invalid.url.com);
  Console.ReadKey();
}

async static Task DownloadAsync(string url)
{
  using (var client = new System.Net.Http.HttpClient())
  {
    string text = await client.GetStringAsync(url);
    Console.WriteLine("Downloaded {0} chars", text.Length);
  }
}
like image 67
Stephen Cleary Avatar answered Oct 19 '22 11:10

Stephen Cleary