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
?
AnAggregateException
is 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 theInnerExceptions
property of theAggregateException
. Each element in theInnerExceptions
collection represents an individual exception that occurred during the asynchronous operations.