async Samples 5: Exceptions and async methods

To some degree, the async samples present an overly simplified view of exception handling in async methods. Despite that, it is a good overview of how the team wanted to make the async methods behave as much like serial methods as possible. First, exceptions will propagate from async methods to the code that awaits the async result:

        public async void AsyncTryCatch()
{
try
{
WriteLinePageTitle(await new WebClient().DownloadStringTaskAsync(
new Uri("http://www.weather.gov/clmitae/")));
}
catch
{
Console.WriteLine("Error loading page.");
}
}

Exceptions will propagate out to the caller that is awaiting the completion of an async call. In the example above, DownloadStringTaskAsync() throws an exception, and the awaiting code catches is.

The same rules apply for finally blocks:

        public async void AsyncTryFinally()
{
Console.WriteLine("Download process beginning...");
try
{
WriteLinePageTitle(await DownloadStringTaskSlowNetworkAsync(
new Uri("http://www.weather.gov"), cts.Token));
WriteLinePageTitle(await DownloadStringTaskSlowNetworkAsync(
new Uri("http://www.weather.gov/clmitae/"), cts.Token));
WriteLinePageTitle(await DownloadStringTaskSlowNetworkAsync(
new Uri("http://www.weather.gov/rss/"), cts.Token));
}
catch
{
Console.WriteLine("There was an error downloading the pages.");
}
finally
{
Console.WriteLine("Download process completed.");
}
Console.WriteLine("Success!");
}
 
These two samples work because exceptions thrown from inside a Task-returning method can be caught by the code awaiting that task:
 
        public async void AsyncThrow()
{
var uris = new List<Uri> {
new Uri("http://www.weather.gov/climate/"),
new Uri("http://www.weather.gov"),
new Uri("http://www.weather.gov/rss/") };

try
{
await CheckPageSizes(uris);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}

public async Task CheckPageSizes(IList<Uri> uris)
{
foreach (var uri in uris)
{
string page = await new WebClient().DownloadStringTaskAsync(uri);

if (page.Length < 50000)
thrownew Exception(String.Format("{0} is too small!", uri));

Console.WriteLine("{0} contains {1} bytes.", uri, page.Length);
}
}

What’s not covered here is any of the more complicated flows that you’ll need to determine which of the async tasks caused the error or how many of the tasks did cause an error. That’s handled by AggregateExceptions, and is the subject for another day.

Created: 3/23/2011 12:08:49 PM

Current Projects

I create content for .NET Core. My work appears in the .NET Core documentation site. I'm primarily responsible for the section that will help you learn C#.

All of these projects are Open Source (using the Creative Commons license for content, and the MIT license for code). If you would like to contribute, visit our GitHub Repository. Or, if you have questions, comments, or ideas for improvement, please create an issue for us.

I'm also the president of Humanitarian Toolbox. We build Open Source software that supports Humanitarian Disaster Relief efforts. We'd appreciate any help you can give to our projects. Look at our GitHub home page to see a list of our current projects. See what interests you, and dive in.

Or, if you have a group of volunteers, talk to us about hosting a codeathon event.