.NET 4.0任务:在Task.ContinueWith中对UI线程的Rethrow异常

时间:2011-08-04 13:41:14

标签: .net .net-4.0 task

我有一个WPF应用程序,我使用System.Threading.Tasks进行长时间运行的WCF调用。我通过向Application.Current.DispatcherUnhandledException添加处理程序来捕获未处理的异常。

我创建了一个任务,其中使用以下代码在UI线程上运行ContinueWith函数:

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

当任务中发生异常时,我想重新抛出异常,以便DispatcherUnhandledException处理程序可以处理它。但是当我重新抛出异常时,如上所示,它会崩溃我的应用程序并且不会调用DispatcherUnhandledException。

如何在UI线程上重新抛出异常,以便调用DispatcherUnhandledException处理程序?

当我使用BackgroundWorker时,重新抛出异常就是这样。基本上,我希望将BackgroundWorker替换为Task,因为Task有一些我想要利用的非常好的功能。

2 个答案:

答案 0 :(得分:7)

解决此问题的一种方法是在语句中包含的Lambda表达式中重新抛出异常。类似的东西:

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

我不建议这样做虽然有点犯规,但确实回答了这个问题!

你可以选择做与SynchronizationContext.Post讨厌的事情。

答案 1 :(得分:1)

我遇到了完全相同的问题,尽管在我的情况下,应用程序不会崩溃,但是,从不引发Application.DispatcherUnhandledException事件。我也尝试使用AppDomain.CurrentDomain.UnhandledException,它也不起作用。我喜欢使用顶级异常处理程序来处理可能在许多地方发生的全局错误。

我有一个我开发的库,它使用基于事件的异步模式(EAP),我正在改变使用基于任务的异步模式(TAP),而不是为.NET 4.5做准备,它有更好的异步支持这是基于任务。使用EAP,Completed事件在UI线程上执行,这很好。使用Tasks,您必须使用上面提到的TaskScheduler.FromCurrentSynchronizationContext()。我验证了ContinueWith代码在UI线程上运行,我从那里抛出异常。所以,我对发生的事情感到茫然。

希望这将在.NET 4.5中修复,希望我从EAP切换到TAP还为时过早。我喜欢你可以用TAP更好地创造事物的事实。不得不调用Dispatcher.Invoke(),但很多事情似乎都很糟糕。