Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Has anybody faced with cases, when AggregateException.InnerExceptions.Count > 1?

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.

like image 793
Dennis Avatar asked Apr 23 '13 13:04

Dennis


2 Answers

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);
like image 164
Ani Avatar answered Oct 04 '22 00:10

Ani


As Ani has said these AggregateExceptions can be created via multiple successive Tasks 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 InnerExceptions as required.

I hope this helps.

like image 41
MoonKnight Avatar answered Oct 03 '22 23:10

MoonKnight