Alex Zhukovskiy
Alex Zhukovskiy

Reputation: 10035

Async/Await exception handling

My question is based on article Best Practices in Asynchronous Programming

So i have this code

    async static void AsyncVersion()
    {
        Stopwatch sw = Stopwatch.StartNew();
        string url1 = "http://rsdn.ru";
        string url2 = "http://gotdotnet.ru";
        string url3 = "http://blogs.msdn.com";

        var webRequest1 = WebRequest.Create(url1);
        Console.WriteLine("Before webRequest1.GetResponseAsync(). Thread Id: {0}",
            Thread.CurrentThread.ManagedThreadId);
        ...

so this code throws exception, for example when i haven't inet connection. So when i'm following msdn's guidances and change signature of method to Task (instead of void), but after this it devour all exceptions, but hey aren't handle by external catch block.

Entire code is below

using System;
using System.Diagnostics;
using System.Net;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApplication8
{
    class Program
    {
        async static Task AsyncVersion()
        {
            Stopwatch sw = Stopwatch.StartNew();
            string url1 = "http://rsdn.ru";
            string url2 = "http://gotdotnet.ru";
            string url3 = "http://blogs.msdn.com";

            var webRequest1 = WebRequest.Create(url1);
            Console.WriteLine("Before webRequest1.GetResponseAsync(). Thread Id: {0}",
                Thread.CurrentThread.ManagedThreadId);

            var webResponse1 = await webRequest1.GetResponseAsync();
            Console.WriteLine("{0} : {1}, elapsed {2}ms. Thread Id: {3}", url1,
                webResponse1.ContentLength, sw.ElapsedMilliseconds,
                Thread.CurrentThread.ManagedThreadId);

            var webRequest2 = WebRequest.Create(url2);
            Console.WriteLine("Before webRequest2.GetResponseAsync(). Thread Id: {0}",
                Thread.CurrentThread.ManagedThreadId);

            var webResponse2 = await webRequest2.GetResponseAsync();
            Console.WriteLine("{0} : {1}, elapsed {2}ms. Thread Id: {3}", url2,
                webResponse2.ContentLength, sw.ElapsedMilliseconds,
                Thread.CurrentThread.ManagedThreadId);

            var webRequest3 = WebRequest.Create(url3);
            Console.WriteLine("Before webRequest3.GetResponseAsync(). Thread Id: {0}",
                Thread.CurrentThread.ManagedThreadId);
            var webResponse3 = await webRequest3.GetResponseAsync();
            Console.WriteLine("{0} : {1}, elapsed {2}ms. Thread Id: {3}", url3,
                webResponse3.ContentLength, sw.ElapsedMilliseconds,
                Thread.CurrentThread.ManagedThreadId);
        }
        static void Main(string[] args)
        {

            try
            {
                Console.WriteLine("Main thread id: {0}", Thread.CurrentThread.ManagedThreadId);
                Task task = new Task(() => AsyncVersion());
                task.Start();
                Console.WriteLine("Right after AsyncVersion() method call");
                //Ожидаем завершения асинхронной операции
                task.Wait();
                Console.WriteLine("Asyncronous task finished!");

            }
            catch (Exception e)
            {
                //Все исключения в TPL пробрасываются обернутые в AggregateException
                Console.WriteLine("Exceptopn: {0}", e.Message);
            }
            Console.ReadLine();
        }
    }
}

old version:

using System;
using System.Diagnostics;
using System.Net;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApplication8
{
    class Program
    {
        async static void AsyncVersion()
        {
            Stopwatch sw = Stopwatch.StartNew();
            string url1 = "http://rsdn.ru";
            string url2 = "http://gotdotnet.ru";
            string url3 = "http://blogs.msdn.com";

            var webRequest1 = WebRequest.Create(url1);
            Console.WriteLine("Before webRequest1.GetResponseAsync(). Thread Id: {0}",
                Thread.CurrentThread.ManagedThreadId);

            var webResponse1 = await webRequest1.GetResponseAsync();
            Console.WriteLine("{0} : {1}, elapsed {2}ms. Thread Id: {3}", url1,
                webResponse1.ContentLength, sw.ElapsedMilliseconds,
                Thread.CurrentThread.ManagedThreadId);

            var webRequest2 = WebRequest.Create(url2);
            Console.WriteLine("Before webRequest2.GetResponseAsync(). Thread Id: {0}",
                Thread.CurrentThread.ManagedThreadId);

            var webResponse2 = await webRequest2.GetResponseAsync();
            Console.WriteLine("{0} : {1}, elapsed {2}ms. Thread Id: {3}", url2,
                webResponse2.ContentLength, sw.ElapsedMilliseconds,
                Thread.CurrentThread.ManagedThreadId);

            var webRequest3 = WebRequest.Create(url3);
            Console.WriteLine("Before webRequest3.GetResponseAsync(). Thread Id: {0}",
                Thread.CurrentThread.ManagedThreadId);
            var webResponse3 = await webRequest3.GetResponseAsync();
            Console.WriteLine("{0} : {1}, elapsed {2}ms. Thread Id: {3}", url3,
                webResponse3.ContentLength, sw.ElapsedMilliseconds,
                Thread.CurrentThread.ManagedThreadId);
        }
        static void Main(string[] args)
        {

            try
            {
                Console.WriteLine("Main thread id: {0}", Thread.CurrentThread.ManagedThreadId);
                Task task = new Task(AsyncVersion);
                task.Start();
                Console.WriteLine("Right after AsyncVersion() method call");
                //Ожидаем завершения асинхронной операции
                task.Wait();
                Console.WriteLine("Asyncronous task finished!");

            }
            catch (System.AggregateException e)
            {
                //Все исключения в TPL пробрасываются обернутые в AggregateException
                Console.WriteLine("AggregateException: {0}", e.InnerException.Message);
            }
            Console.ReadLine();
        }
    }
}

Upvotes: 1

Views: 5570

Answers (1)

svick
svick

Reputation: 245008

new Task(() => AsyncVersion())

This is the problematic part. The Task constructor doesn't understand async, so it ignores the Task returned from AsyncVersion. (The fact that you had to use lambda instead of writing AsyncVersion directly should have alerted you that something weird is happening.)

You have several options how to fix this (best options last):

  1. Use Task<Task> and Wait() for the inner Task too:

    Task<Task> task = new Task<Task>(AsyncVersion);
    task.Start();
    task.Result.Wait();
    
  2. Use Unwrap() to change the Task<Task> to Task that represents both Tasks:

    Task<Task> task = new Task<Task>(AsyncVersion);
    task.Start();
    task.Unwrap().Wait();
    
  3. Use Task.Run(), which does understand async:

    Task task = Task.Run(() => AsyncVersion());
    task.Wait();
    
  4. Don't start a Task at all, just call the async method:

    Task task = AsyncVersion();
    task.Wait();
    

Upvotes: 10

Related Questions