I'm wondering, has anybody faced with cases, when AggregateException.InnerExceptions.Count
> 1?
E.g., TPL wraps exception, that was raised in task body, in AggregateException
. But I never saw situations, when there was more than one inner exception.
How this can be achieved with TPL?
How this can be achieved with any FCL (or another widely used library) classes (samples will be useful)?
I know, that there's possibility to build such instance of AggregateException
, but the question is about a practice. I'm asking about this, because I want to understand, what is the best way to handle AggregateException
.
The typical case is when a task is dependent on multiple tasks, and more than one of those tasks throw exceptions. For example:
var t1 = Task.Factory.StartNew( () => { throw new Exception(); } );
var t2 = Task.Factory.StartNew( () => Console.WriteLine("Innocuous") );
var t3 = Task.Factory.StartNew( () => { throw new Exception(); } );
// Output: 2
var t4 = Task.WhenAll(t1, t2, t3)
.ContinueWith(t => Console.WriteLine(t.Exception.InnerExceptions.Count),
TaskContinuationOptions.OnlyOnFaulted);
As Ani has said these AggregateExceptions
can be created via multiple successive Task
s using continuations to observer the exceptions.
Task t1 = Task.Factory.StartNew(() => { throw new Exception(); });
Task t2 = Task.Factory.StartNew(() => { throw new Exception(); });
Task t3 = Task.WhenAll(t1, t2)
.ContinueWith(t => t.Exception.InnerExceptions.Count(),
TaskContinuationOptions.OnlyOnFaulted);
Typically you would handle the AggregateException
within a continuation. A continuation can find out if an exception was thrown by the antecedent Task
by the antecedent task's exception property. The following prints the results of a NullReferenceException
to the console
Task task1 = Task.Factory.StartNew (() => { throw null; });
Task task2 = task1.ContinueWith (ant => Console.Write(ant.Exception());
If task1
throws an exception and this exception is not captured/queried by the continuation it is considered unhandled and the application dies. With continuations it is enough to establish the result of the task via the Status
keyword
asyncTask.ContinueWith(task =>
{
// Check task status.
switch (task.Status)
{
// Handle any exceptions to prevent UnobservedTaskException.
case TaskStatus.RanToCompletion:
if (asyncTask.Result)
{
// Do stuff...
}
break;
case TaskStatus.Faulted:
if (task.Exception != null)
mainForm.progressRightLabelText = task.Exception.Flatten().Message;
else
mainForm.progressRightLabelText = "Operation failed!";
default:
break;
}
}
Where in the above I only expect a single exception - to ensure this is the case I can call Flatten()
. If you are expecting other types of exceptions you can iterate through the InnerException
s as required.
I hope this helps.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With