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
Exceptions are propagated when you use one of the static or instance Task. Wait methods, and you handle them by enclosing the call in a try / catch statement. If a task is the parent of attached child tasks, or if you are waiting on multiple tasks, multiple exceptions could be thrown.
When exceptions happen, all the exceptions are re-thrown by the calling thread. To do that they're wrapped inside AggregateException and returned to the caller. So when we await a task, we only get the first exception from a collection of exceptions that might exist on a task.
Use a try block around the statements that might throw exceptions. Once an exception occurs in the try block, the flow of control jumps to the first associated exception handler that is present anywhere in the call stack. In C#, the catch keyword is used to define an exception handler.
ContinueWith(Action<Task,Object>, Object, TaskScheduler)Creates a continuation that receives caller-supplied state information and executes asynchronously when the target Task completes.
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.
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