How to manage properly an exception in a Task with ContinueWith

11.5k Views Asked by At

After reading information about task and exepcion management, I am using this code to manage an exception thrown in a Task:

Task<Object> myTask = Task.Factory.StartNew<Object>(doTask, CancellationToken.None,   TaskCreationOptions.None, TaskScheduler.Default);
myTask .ContinueWith(task => afterTask(task), TaskScheduler.FromCurrentSynchronizationContext());

Where doTask and AfterTask are:

private <Object> doTask() {
    throw new Exception("BOOM");
}

private afterTask(Task<Object> aTask) {

        if (aTask.IsFaulted)
        {
            MessageBox.Show(aTask.Exception.InnerException.Message);
        }
        else //whatever
}

When Exception Boom is thrown the Visual Studio shows an alert informing that an exception has not been caught but if I continue executing the exception is processed in the afterTask function.

Is this code correct or I missunderstood some basic behaviour of the task? There is any way to avoid the alert from the debugger that the execption has not been caught? Is a bit annoying...

Thanks in advance

2

There are 2 best solutions below

3
On BEST ANSWER

Try this instead:

 task.ContinueWith(
            t =>
            t.Exception.Handle(ex =>
                                   {
                                       logger.Error(ex.Message, ex);
                                       return false;
                                   })

            , TaskContinuationOptions.OnlyOnFaulted
            );

By using the TaskContinuationOptions.OnlyOnFaulted, you run your ContinueWith block only if an exception is thrown by the original task.

Aditionally, you can choose whether to return true or false from the lambda passed to Handle, indicating whether the exception has been handled or not. In my case, I didn't want to stop the exception from propagating. You might want to change it to return true in your case.

0
On
        try
        {
            var t1 = Task.Delay(1000);

            var t2 = t1.ContinueWith(t =>
            {
                Console.WriteLine("task 2");
                throw new Exception("task 2 error");
            }, TaskContinuationOptions.OnlyOnRanToCompletion);

            var t3 = t2.ContinueWith(_ =>
            {
                Console.WriteLine("task 3");
                return Task.Delay(1000);
            }, TaskContinuationOptions.OnlyOnRanToCompletion).Unwrap();

            // The key is to await for ALL tasks rather than just
            // the first or last task.
            await Task.WhenAll(t1, t2, t3);
        }
        catch (AggregateException aex)
        {
            aex.Flatten().Handle(ex =>
                {
                    // handle your exceptions here
                    Console.WriteLine(ex.Message);
                    return true;
                });
        }