How can I mark an exception thrown in a task as handled. The problem is when I call the Wait()
method of a task, it will throw an AggregateException
even when I have already handled the AggregateException
a long time ago.
The following code snippet shows the problem I want to solve. I my original code I handle the AggregateException
in one part of my code and I call the Wait()
method in another part of my code. But the problem is the same.
static void Main(string[] args)
{
Task task = null;
try
{
task = new Task(() =>
{
Console.WriteLine("Task started");
Thread.Sleep(1000);
throw new InvalidOperationException("my test exception");
});
task.ContinueWith(t =>
{
Console.WriteLine("Task faulted");
AggregateException ae = t.Exception;
ae.Flatten().Handle(ex =>
{
if (typeof(InvalidOperationException) == ex.GetType())
{
Console.WriteLine("InvalidOperationException handled --> " + ex.Message);
return true;
}
return false;
});
}, TaskContinuationOptions.OnlyOnFaulted);
task.Start();
Thread.Sleep(2000);
task.Wait();
}
catch (AggregateException ae)
{
Console.WriteLine("AggregateException thrown again!!! Why???");
ae.Flatten().Handle(ex =>
{
Console.WriteLine(ex.Message);
return true;
});
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Console.WriteLine("Finished");
Console.Read();
}
The code above produces the following output:
- Task started
- Task faulted
- InvalidOperationException handled --> my test exception
- AggregateException thrown again!!! Why???
- my test exception
- Finished
When a faulted task is
Wait
ed the exception is rethrown. It would be unreliable design if an exception would be thrown just sometimes.But, if you're adding a continuation that handles the exception and you don't want it thrown again then simply don't
Wait
that task again.Wait
the continuation task (that you're currently not using) instead. It would only complete after the original task completed and if you need the result simply have the continuation return that. This way the exception would be handled only once:Note: That will throw a
TaskCanceledException
when the original task doesn't throw an exception because the continuation is canceled (due toTaskContinuationOptions.OnlyOnFaulted
). To avoid that simply remove the flag and check whethert.IsFaulted
.