I have a task with a continuation to handle errors:
var uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
var loadTask = Task<List<OrderItemViewModel>>.Factory.StartNew(() =>
{
throw new Exception("derp");
});
var errorContinue = loadTask.ContinueWith(t =>
{
MainViewModel.RemoveViewModel(this);
}, CancellationToken.None, TaskContinuationOptions.OnlyOnFaulted, uiScheduler);
The continuation is hit, but a few seconds later I receive this error in the application:
A Task's exception(s) were not observed either by Waiting on the Task or accessing its Exception property. As a result, the unobserved exception was rethrown by the finalizer thread.
Is this related to the uiScheduler? The solution to the similar question is basically what I'm doing A Task's exception(s) were not observed either by Waiting on the Task or accessing its Exception property. As a result, the unobserved exception was
An “unobserved” exception is one that's stored into the task but then never looked at in any way by the consuming code. There are many ways of observing the exception, including Wait()'ing on the Task, accessing a Task<TResult>'s Result, looking at the Task's Exception property, and so on.
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 using await, it's going to unwrap the first exception and return it, that's why we don't hit the catch (AggregateException e) line. But if we use something like the below code sample, we catch the AggregateException , note that it's not a good idea since we're blocking the running thread.
You need to actually handle (or at least observe) the exception:
var errorContinue = loadTask.ContinueWith(t =>
{
// Observe/acknowledge the exception.
// You can use t.Wait(), which throws, or just grab the exception
var exception = t.Exception;
MainViewModel.RemoveViewModel(this);
}, CancellationToken.None, TaskContinuationOptions.OnlyOnFaulted, uiScheduler);
This is because of this line of the documentation on exception handling in the TPL:
If you do not wait on a task that propagates an exception, or access its Exception property, the exception is escalated according to the .NET exception policy when the task is garbage-collected.
In your case, you have a continuation, but you never actually "wait on the exception" or access it's exception property. The reason my answer (in the related question you posted) works is that I'm actually using the Exception property on the Task passed through the continuation.
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