How to manage properly an exception in a Task with ContinueWith
Asked Answered
M

2

8

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

Marcus answered 17/9, 2013 at 9:48 Comment(0)
S
22

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.

Silverts answered 17/9, 2013 at 9:52 Comment(3)
Thank you very much for your super quick answer. Although the code works it doesn't prevent the debugger from alerting that the exception has not been caught when throwing BOOM. Is there any benefit from using that code instead the one i posted?Marcus
In visual studio Debug->Exceptions-> uncheck commonlanguageruntimeexceptions thrown checkbox click okCanal
The main advantage is the fact that the ContinueWith task will only run when an exception is thrown. In the sample you posted, the task would always be run. The second advantage is readability. To prevent those VS popups, I'd try this: #2174497Silverts
S
-3
        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;
                });
        }
Suds answered 18/12, 2014 at 2:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.