C# > Asynchronous Programming > Tasks and async/await > Exception Handling in Async Code
Exception Handling with Task.WhenAll and AggregateException
This snippet demonstrates how to handle exceptions when using Task.WhenAll. Task.WhenAll aggregates exceptions into an AggregateException, which needs to be handled appropriately.
Implementation
The SimulateAsyncOperation method simulates an asynchronous operation that may or may not throw an exception. The Main method creates a list of tasks and uses Task.WhenAll to wait for all of them to complete. If any of the tasks throw an exception, Task.WhenAll will throw an AggregateException containing all the inner exceptions. The code then iterates through the InnerExceptions property of the AggregateException to handle each individual exception.
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
public class TaskWhenAllExceptionHandler
{
public static async Task SimulateAsyncOperation(int id, bool throwException)
{
Console.WriteLine($"Task {id}: Started");
await Task.Delay(1000); // Simulate some work
if (throwException)
{
throw new InvalidOperationException($"Task {id}: Simulated exception.");
}
Console.WriteLine($"Task {id}: Completed successfully.");
}
public static async Task Main(string[] args)
{
List<Task> tasks = new List<Task>
{
SimulateAsyncOperation(1, false),
SimulateAsyncOperation(2, true),
SimulateAsyncOperation(3, false),
SimulateAsyncOperation(4, true)
};
try
{
await Task.WhenAll(tasks);
Console.WriteLine("All tasks completed successfully.");
}
catch (AggregateException ex)
{
Console.WriteLine("AggregateException caught:");
foreach (var innerException in ex.InnerExceptions)
{
Console.WriteLine($" {innerException.GetType().Name}: {innerException.Message}");
}
}
catch (Exception ex)
{
Console.WriteLine($"Exception caught: {ex.Message}");
}
}
}
Concepts Behind the Snippet
Task.WhenAll is used to wait for multiple tasks to complete. When one or more of these tasks throw an exception, these exceptions are aggregated into an AggregateException. This design pattern allows the application to process multiple asynchronous operations concurrently and handle any errors that may occur in a consolidated manner. Proper handling of AggregateException is crucial for managing failures within asynchronous workflows.
Real-Life Use Case
This pattern is useful when performing multiple independent operations simultaneously, such as downloading multiple files, querying multiple databases, or processing multiple API requests. If any of these operations fail, the application can collect all the errors and present a comprehensive error report to the user or retry the failed operations.
Best Practices
AggregateException when using Task.WhenAll or Task.WhenAny.InnerExceptions property of the AggregateException to handle each individual exception.
Interview Tip
Be prepared to explain how Task.WhenAll handles exceptions and why it's important to handle the AggregateException. Discuss the benefits of using Task.WhenAll for parallel processing and the challenges of handling exceptions in a concurrent environment.
When to Use Them
Use Task.WhenAll when you need to wait for multiple independent tasks to complete and you want to handle any exceptions that may occur in a consolidated manner. This is particularly useful for performance-critical applications where parallel processing is essential.
Alternatives
Instead of Task.WhenAll, you can use Task.WhenAny to wait for the first task to complete. Another alternative is to use a Parallel.ForEach loop to process multiple items concurrently. However, Parallel.ForEach does not provide as robust exception handling as Task.WhenAll.
Pros
AggregateException, making it easier to handle multiple errors.
Cons
AggregateException to process individual exceptions.
FAQ
-
What is an
AggregateException?
AnAggregateExceptionis an exception that contains a collection of other exceptions. It is typically thrown by methods that perform multiple asynchronous operations in parallel and need to report multiple errors. -
How do I access the individual exceptions within an
AggregateException?
You can access the individual exceptions by iterating through theInnerExceptionsproperty of theAggregateException. Each element in theInnerExceptionscollection represents an individual exception that occurred during the asynchronous operations.