Task.Run 中的全局错误处理用于实时用户通知

Global Error Handling in Task.Run for realtime User ntofication

我有一个 wpf c# 应用程序。

我通常使用全局错误处理程序来捕获所有错误:

private void Application_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
    try
    {
        Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() => Xceed.Wpf.Toolkit.MessageBox.Show(e.Exception.ToString(), "Error",
          MessageBoxButton.OK, MessageBoxImage.Error)));
        e.Handled = true;
        InformedWorkerDataService.Common.Shared.RecordMessage(e.Exception.ToString(), true);
    }
    finally { }
}

但是,如果从 task.run 'bit of code' 开始并抛出错误,那么我观察到该错误未被捕获:

Task.Run(() =>
{
    throw and error here    
});

所以我必须放入一个 'Try-Catch' 东西来捕获它:

Task.Run(() =>
{
    try
    {
        throw an error here
    }
    catch (Exception ex)
    {
        do  something with error
    }
});

~ 这破坏了拥有全局错误处理程序的对象 但是,如果我使用这种方法:

TaskScheduler.UnobservedTaskException += (s, e) => {
    e.Exception  //The Exception that went unobserved.
    e.SetObserved(); //Marks the Exception as "observed," thus preventing it from triggering exception escalation policy which, by default, terminates the process.
};

...它将执行我的全局异常处理,但如果我想实时通知用户错误,它就不会做得很好,因为它在一个单独的线程上。

什么是好的折衷方案?

不幸的是,TaskScheduler.UnobservedTaskException 不能保证在抛出异常的情况下实时触发。这意味着使用此处理程序进行用户通知可能会非常混乱,因为用户操作和错误通知不会同步发生。对于 'unexpected' 任务异常的用户驱动处理,您可以创建如下辅助方法并使用 TaskEx.Run 而不是 Task.Run:

public static class TaskEx
{
    public static Task Run(Action function)
    {
        return Task.Run(() =>
        {
            try
            {
                function();
            }
            catch (Exception ex)
            {
                TraceEx.TraceException(ex);
                //Dispatch your MessageBox etc.
            }
        });
    }
}

显然,这不像添加全局处理程序那么简单(出于跟踪目的仍应这样做)但足够简单,可以在 UI 驱动代码中实现。