Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

.NET 4.0 Tasks: Rethrow Exception to UI Thread in Task.ContinueWith

I have a WPF application, where I make a long-running WCF call using the System.Threading.Tasks. I catch unhandled exceptions by adding a handler to Application.Current.DispatcherUnhandledException.

I create a task, where the ContinueWith function runs on the UI thread using the following code:

var task = new Task<T>(func).ContinueWith(t =>
{
    if (t.IsFaulted)
    {
        throw t.Exception.GetBaseException();
    }
    else
    {
        // Show t.Result on UI
    }
}, TaskScheduler.FromCurrentSynchronizationContext());

When an exception occurs in the task, I would like to rethrow the exception so that the DispatcherUnhandledException handler can handle it. But when I rethrow the exception, as shown above, it crashes my app and the DispatcherUnhandledException is not invoked.

How do I rethrow the exception on the UI thread so that the DispatcherUnhandledException handler is invoked?

When I was using the BackgroundWorker, rethrowing the exception did exactly this. Basically, I am looking to replace BackgroundWorker with Task, since Task has some really nice features I would like to take advantage of.

like image 430
Mas Avatar asked Aug 04 '11 13:08

Mas


2 Answers

One way to solve this, is by rethrowing the Exception in a Lambda expression contained within the statement. Something like:

Exception ex = t.Exception;
Dispatcher.CurrentDispatcher.BeginInvoke(new Action(() => { throw ex; }));

I don't recommend that though as it is a bit foul, but it does answer the question!

You could alternatively do something similarly as nasty with SynchronizationContext.Post.

like image 72
RichardOD Avatar answered Nov 14 '22 20:11

RichardOD


I'm having the exact same problem although in my case, the application doesn't crash, but, the Application.DispatcherUnhandledException event is never raised. I also tried using AppDomain.CurrentDomain.UnhandledException which doesn't work either. I like having a top-level exception handler to handle global errors that can occur in many places.

I have a library that I developed that uses the Event-based Asynchronous Pattern (EAP) which I'm changing to use the Task-based Asynchronous Pattern (TAP) instead in preparation for .NET 4.5 which has much better async support which is based on Tasks. With EAP, the Completed event gets executed on the UI thread which is nice. Using Tasks, you have to use TaskScheduler.FromCurrentSynchronizationContext() like you mentioned above. I verified that the ContinueWith code is running on the UI thread and I'm throwing the exception from there. So, I'm at a loss as to what is going on.

Hopefully this will be fixed in .NET 4.5 and hopefully it's not premature for me to switch from EAP to TAP. I like that fact that you can compose things better with TAP. Having to call Dispatcher.Invoke() a lot seems kind of bad though.

like image 44
Jon Miller Avatar answered Nov 14 '22 19:11

Jon Miller