I’m trying to understand async/await in .net8, especially exception handling and I’m running into some confusion, especially regarding the documentation as while it specifies some of the approach it doesn’t give enough examples for me to understand what’s happening.
I’m using the following trivial code just to watch something work:
private static async Task Main(string[] args) {
var sleeps = new int[] { 1, 2, 3, 0 };
var tasks = new List<Task<int>>();
foreach (var t in sleeps)
{
Console.WriteLine("Submitting task: {0}", t);
tasks.Add(sleep(t));
}
Console.WriteLine("All tasks submitted, waiting for all to complete");
try
{
Task.WaitAll(tasks.ToArray());
} catch (DivideByZeroException e)
{
Console.WriteLine("One of the tasks fucked up: {0}", e);
}
Console.WriteLine("All tasks completed, collecting results");
foreach (var t in tasks)
{
Console.WriteLine("Task returned: {0}", t.Result);
}
}
private static async Task<int> sleep(int s)
{
Console.WriteLine("Sleeping for: [ {0} ]", s);
if (s == 0)
{
// this is just to throw something to be caught
throw new DivideByZeroException("0 can't be delayed");
}
await Task.Delay(s * 1000);
Console.WriteLine("tSlept for: [ {0} ]", s);
return s;
}
I’m following documentation from here: https://learn.microsoft.com/en-us/dotnet/csharp/asynchronous-programming/#asynchronous-exceptions and here: https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/exceptions/creating-and-throwing-exceptions#exceptions-in-task-returning-methods
According the docs I should try to throw exceptions in my async functions BEFORE entering the async portion of the code. Which you can see in my example I am, I am throwing a ZeroDivision exception before awaiting the Task.Delay.
When I run this code in visual studio, I would expect to hit my DivideByZeroException catch block, but instead I get a SystemAggregateException, which I understand is how .net collects all of the async exceptions, however the documentation explicitly states: When code awaits a faulted task, the first exception in the AggregateException.InnerExceptions collection is rethrown
. However, I am not getting the DivideByZero exception thrown at all, instead I am getting 2 SystemAggregate exceptions throw sequentially each with their first innerException being the DivideByZero exception.
What is going on here.
I have also coded the breakfast example here: https://learn.microsoft.com/en-us/dotnet/csharp/asynchronous-programming/ and added the toaster on fire there is even more confusing, in that I DO NOT get an exception throw anywhere when I explicitly throw one. I must inspect the Task.Exception to see if it was thrown.
So can anyone explain what is happening here?
What is the approach I would use if I wanted to submit 5 async tasks, wait for all of them to complete and then iterate over them to inspect either their Result
or Exception
properties? I am not understanding when to try/catch, when to inspect Task.Exception and why I’m getting SystemAggregate exceptions in my example code.