8

All, there are many question on the above topic but I believe this is sufficiently different to warrant a new question. I have the following Task and a continuation to deal with a variety of task Status; TaskStatus.RanToCompletion, TaskStatus.Canceled and of course the AggregateException via TaskStatus.Faulted. The code looks like

Task<bool> asyncTask = Task.Factory.StartNew<bool>(() =>
    asyncMethod(uiScheduler, token, someBoolean), token);

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.InnerException.Message;
            else
                mainForm.progressRightLabelText = "Operation failed!";
        default:
            break;
    }
}

This all works well, but I am concerned whether or not I am doing this right, as there is the possibility of an AggregateException being thrown from within the continuation - what then?

I do not want to Wait on my asyncTask nor the continuation as this will block the return to the UI Thread. To catch any exceptions thrown from within a continuation can't mean I have to do something like this surely

Task parentTask = Task.Factory.startNew(() => 
    {
        Task<bool> asyncTask = Task.Factory.StartNew<bool>(() =>
            asyncMethod(uiScheduler, token, someBoolean), token);

        Task continueTask = asyncTask.ContinueWith(task =>
            {
                // My continuation stuff...   
            }

        try
        {
            continueTask.Wait();
        }
        catch(AggregateException aggEx)
        { 
            // Some handling here...
        }
    });

would this even work? What is best practice here?

As always, thanks for your time.

niktehpui
  • 560
  • 3
  • 15
MoonKnight
  • 23,214
  • 40
  • 145
  • 277
  • I've seen tasks that "ran to completion" when in fact they threw an AggregateException. That kind of error handling doesn't work. Why not just use a try/catch? – Louis Kottmann Mar 27 '12 at 09:52
  • You mean in the method that is called on the background thread, or in the actual continuation delegate method? – MoonKnight Mar 27 '12 at 09:53

2 Answers2

12

You can use traditional try/catch within your delegates watching for AggregateException or you can chain on specific continuations that will only ever run if the antecedent has faulted using the TaskContinuationOptions.OnlyOnFaulted option. The latter approach allows for very clean task workflows to be defined. For example:

Task myRootTask = ....;

myRootTask.ContinueWith(rootAntecdent =>
{
    // this will only be executed if the antecedent completed successfully, no need to check for faults
},
TaskContinuationOptions.OnlyOnRanToCompletion);

myRootTask.ContinueWith(rootAntecedent =>
{
    // this will only be executed if the antecedent faulted, observe exception and handle accordingly
},
TaskContinuationOptions.OnlyOnFaulted);
Drew Marsh
  • 33,111
  • 3
  • 82
  • 100
2

Msdn has a fairly well written "How to" on the subject: here

You will notice they simply use a try/catch(AggregateException) block, then filter the exception they know how to handle in ae.Handle(lambda) and make the app stop if there are some left that aren't handleable.

Louis Kottmann
  • 16,268
  • 4
  • 64
  • 88
  • I am aware of examples like the ones your link provides and do not have an issue with eception handling _this way_. My issue is how to handle exeptions thrown from continuations without enclosing the entire continuation delegate with a try catch, then again this might be the only way. I want to know best paractice for real world code, not Microsoft toy code best practice. Cheers. – MoonKnight Mar 27 '12 at 10:04
  • The OP wants to know how to do this without using Wait. The examples all Wait for the Task. Try this[http://msdn.microsoft.com/en-us/library/dd997415.aspx] link. – Jordan Morris Nov 04 '13 at 21:10