2 ways to handle exception with C#’s Task.WhenAll

Photo by Jason Dent on Unsplash

2 ways to handle exception with C#’s Task.WhenAll

Exception handling in async programming is bit of a tedious task. Here, we will look 2 ways to handle it properly while using Task.WhenAll method.

Task is a unit of work which is being executed on a separate thread by the scheduler. Programmer will no longer have to manage the low level threads. A thread from the thread pool will execute the created task.

Following are ways to handle the exceptions :-

  • 1st way to handle the exception

      var tasks = new List<Task>();
    
      Func<Task> function1 = async () =>
      {
          await Task.Delay(2000); // To show some long running tasks.
          throw new Exception(message: "Task Exception1");
      };
    
      Func<Task> function2 = async () =>
      {
          await Task.Delay(2000); // To show some long running tasks.
          throw new IndexOutOfRangeException(message: "Task Exception2");
      };
    
      var oneTask = await Task.Factory.StartNew(function1);
      var TwoTask = await Task.Factory.StartNew(function2);
    
      tasks.Add(oneTask);
      tasks.Add(TwoTask);
    
      try
      {
          await Task.WhenAll(tasks);
      }
      catch (Exception ex)
      {
          Console.WriteLine(ex);
      }
    

When we run the above, we get exception message as Task Exception1, we didn’t get Task Exception2, as await will unwrap the first exception and return it. It means we are not getting the details of each of our failed tasks.

  • 2nd way to handle the exception

Here, we have captured the task returned from the Task.WhenAll and await on it.

var tasks = new List<Task>();

Func<Task> function1 = async () =>
{
    await Task.Delay(2000); // To show some long running tasks.
    throw new Exception(message: "Task Exception1");
};

Func<Task> function2 = async () =>
{
    await Task.Delay(2000); // To show some long running tasks.
    throw new IndexOutOfRangeException(message: "Task Exception2");
};

var oneTask = await Task.Factory.StartNew(function1);
var TwoTask = await Task.Factory.StartNew(function2);

tasks.Add(oneTask);
tasks.Add(TwoTask);
Task allTasks = null; // To capture the task returned from WhenAll method
try
{
    allTasks = Task.WhenAll(tasks);
    await allTasks; // awaiting the task here 
}
catch (Exception ex)
{
   // Capturing all the exceptions from the task
    AggregateException exception = allTasks.Exception; 
    foreach (var error in exception.InnerExceptions) 
    {
        Console.WriteLine(error);
    } 
}

When we run the above code, we are able to get the exceptions returned from both of our method