I have read a lot on how to handle exceptions in TPL but don't really understand.
Lets take this example code:
var task1 = new Task(() => { throw new Exception("Throw 1"); });
var task2 = task1.ContinueWith(t => Console.WriteLine("Catch 1:{0}", t.Exception.Message),
TaskContinuationOptions.OnlyOnFaulted);
var task3 = task2.ContinueWith(t => Console.WriteLine("Continuation"));
task1.Start();
try {
task1.Wait();
}
catch (Exception ex) {
Console.WriteLine("Wait Exception: {0}", ex.Message);
}
I expected this to print
Catch 1
Continuation
But I get
Catch 1
Continuation
Wait Exception
This means that the exception is still considered unhandled when the task completes and the task finalizer will eventually tear down the application.
How do I handle the exception inside the continuation so the finalizer will not throw? At the same time I want the task to remain in the faulted state so wrapping the task in try/catch will not work.
The background is that I want to implement the async event pattern as specified here but with error handling. My complete code looks like this
public IAsyncResult Begin(AsyncCallback callback, object state, Action action) {
var task1 = new Task(action);
var task2 = task1.ContinueWith(t => HandleException(t.Exception),
TaskContinuationOptions.OnlyOnFaulted);
if (callback != null) {
var task3 = task2.ContinueWith(t => callback(t),
TaskScheduler.FromCurrentSynchronizationContext());
var task4 = task3.ContinueWith(t => HandleException(t.Exception),
TaskContinuationOptions.OnlyOnFaulted);
}
task1.Start();
return task;
}
You do your wait on the task that fails, and if you read the documentation on Task.Wait carefully you will see that wait will rethrow the exception in this case.
But if you wait on your task3
everything should work as expected.
Of course you should keep this in mind:
When you use the OnlyOnFaulted option, it is guaranteed that the Exception property in the antecedent is not null. You can use that property to catch the exception and see which exception caused the task to fault. If you do not access the Exception property, the exception will go unhandled. Also, if you attempt to access the Result property of a task that has been canceled or has faulted, a new exception will be raised.
(Reference here)
And finally yet another good source on How to handle exceptions thrown by tasks
I hope this helps.
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