如何捕获和处理 Task.Factory 内部发生的未处理异常

How to capture and handle unhandled exceptions that happens inside Task.Factory

我已经在应用程序启动中编写了这个代码

里面App.xaml.cs

public App()
{
    AppDomain currentDomain = AppDomain.CurrentDomain;

    currentDomain.UnhandledException += new UnhandledExceptionEventHandler(MyHandler);

    DispatcherUnhandledException += App_DispatcherUnhandledException;

    Application.Current.DispatcherUnhandledException += new DispatcherUnhandledExceptionEventHandler(Application_DispatcherUnhandledException);

    TaskScheduler.UnobservedTaskException += new EventHandler<UnobservedTaskExceptionEventArgs>(Application_DispatcherUnhandledException2);

    this.Dispatcher.UnhandledException += Dispatcher_UnhandledException;


}

private void App_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
    writeMessage(e.Exception);
}

private void Dispatcher_UnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
    writeMessage(e.Exception);
}

private static void writeMessage(Exception e)
{
    string srMsg = e.InnerException?.Message;

    if (srMsg != null)
    {
        srMsg += "\r\n\r\nStack\r\n" + e.InnerException?.StackTrace;
    }

    if (srMsg == null)
    {
        srMsg = e.Message + "\r\n\r\nStack\r\n" + e.StackTrace;
    }

    srMsg += "\r\n\r\n*********\r\n\r\n";

    File.AppendAllText("global_errors.txt", srMsg);

}

private static void Application_DispatcherUnhandledException2(object o, UnobservedTaskExceptionEventArgs e)
{
    writeMessage(e.Exception);
}

private static void Application_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
    writeMessage(e.Exception);
}

private static void MyHandler(object sender, UnhandledExceptionEventArgs args)
{
    Exception e = (Exception)args.ExceptionObject;
    writeMessage(e);
}

但是,这仍然不是捕获任务工厂的错误

例如

此线程中的任何提议均无效WPF global exception handler

仅当您通过例如调用 Wait().Result 或访问其 Exception 属性 观察到 Task 时才会抛出异常。

除非您使用 <ThrowUnobservedTaskExceptions> 配置元素恢复到 .NET Framework 4 中的默认行为并终止进程,否则不会抛出未观察到的异常:

<runtime>
  <ThrowUnobservedTaskExceptions enabled="true"/>
</runtime>

如果你真的想捕获异常,你应该在传递给 Task.Factory.StartNew 的委托中进行。您可以按照建议 here.

将此功能包装在扩展方法中

可以通过多种方式获取 StackTrace,具体取决于哪种方式最适合您的需求。无论如何,我建议你尝试以下方法。

  1. 在项目开始时向 AppDomain.FirstChanceException 事件添加回调,例如在您想要 catch/log 的错误发生之前。这可能类似于以下内容:
public static Main()
{
    AppDomain.CurrentDomain.FirstChanceException += CurrentDomain_FirstChanceException;
}

private static void CurrentDomain_FirstChanceException(object sender, FirstChanceExceptionEventArgs e)
{

}
  1. 之后,在CurrentDomain_FirstChanceException方法中添加Environment.StackTrace。它将当前 StackTrace 保存为 string。根据我的测试,它包括 FileNameFileLineNumber.
var currentStackTrace = Environment.StackTrace;

// Now it is on to you on what you want to do with the StackTrace. This could be some kind of logging.

请注意,这将记录 ALLAppDomain 抛出的异常,无论它们是否由代码处理,例如try/catch