I am struggling to better grasp the rationale of exception and error handling in TPL (and with some more luck in .NET 4.5 async/await tasks)
The slightly modified
You should not mix parent/child tasks with async
. They were not designed to go together.
svick already answered this question as part of his (correct) answer to your other question. Here's how you can think of it:
StartNew
gets one exception, which is wrapped into an AggregateException
and placed on the returned Task
.StartNew
gets both AggregateException
s from its child tasks, which it wraps into another AggregateException
on its returned Task
.await
a Task
, the first inner exception is raised. Any others are ignored.You can observe this behavior by saving the Task
s and inspecting them after the exception is raised by await
:
async static Task Test()
{
Task containingTask, nullRefTask, argTask;
try
{
containingTask = Task.Factory.StartNew(() =>
{
nullRefTask = Task.Factory.StartNew(() =>
{
throw new NullReferenceException();
}, TaskCreationOptions.AttachedToParent);
argTask = Task.Factory.StartNew(() =>
{
throw new ArgumentException();
}, TaskCreationOptions.AttachedToParent);
});
await containingTask;
}
catch (AggregateException ex)
{
Console.WriteLine("** {0} **", ex.GetType().Name);
}
}
If you put a breakpoint on WriteLine
, you can see that the exceptions from both child tasks are being placed on the parent task. The await
operator only propagates one of them, so that's why you only catch one.