任务异常管理c#

Task Exception Management c#

我 运行 包含 2 个项目的解决方案:应用程序和 sdk。

通过应用程序,我创建了一个 sdk 实例,以便应用程序可以启动。问题是,当我在任务内部的代码 运行ning 的一部分中遇到异常时,不会抛出任何未处理的异常,因此我的应用程序保持 运行ning 并且没有意识到意外发生SDK.

我在 App 和 SDK 中注册了 AppDomain.CurrentDomain.UnhandledException 的事件,但是如前所述,当任务中抛出异常时,事件处理程序没有被调用。

有什么我遗漏的吗?

Task 抛出未处理的异常时,其执行将终止,您可以检查原始 Task 对象的 IsFaultedException 属性。

有关这些属性的更多信息here and here, and there's an article devoted to exception handling in Tasks on the MSDN

您还在 TaskScheduler 上举办了 UnobservedTaskException 活动。我自己从未使用过它,但阅读它,它应该类似于 AppDomain 上的 UnhandledException 事件。检查一下 on MSDN

The problem is that when I get an Exception in a part of code running inside of a Task, no Unhandled Exception is thrown so my app keeps running and doesn't realise an unexpected is happening in the SDK.

这不完全正确(感谢@l3arnon 的更正):Task 将在 .NET 4.0 和 .NET 4.5 中传播异常,并将触发 UnobservedTaskException。两者之间的区别在于,.NET 4.5 会在异常触发后安静地 吞下异常,而 .NET 4.0 则相反,如果该事件未得到处理,您的进程就会崩溃。

您可以通过“app.configandThrowUnobservedTaskExceptions”改回 .NET 4.0 行为

您可以通过其他几种方法解决此问题:

  1. 在您的代码中使用 await Task.Runawait 将从任务内部解包您的异常。
  2. 如果不想等待,想用"Fire and Forget"的方式,可以附上续篇:

    Task.Run(() => {}).ContinueWith(task => { */ Handle Exceptions here */ },
                                    TaskContinutationOptions.OnlyOnFaulted);
    

两个答案都有些(但不完全)完整。

异步

处理故障任务的最佳方法是使用await异步等待它完成。这将重新抛出原来存储的异常:

try
{
    await task;
}
catch (Exception e)
{
    // handle exception
}

同步

如果您不能这样做(或不想这样做),您也可以使用 task.Wait() 同步等待并抛出包含原始异常的 AggregateException in InnerExceptions 或注册一个处理它的延续(即 task.ContinueWith(t => // handle exception)

UnobservedTaskException

在 .Net 4.0 中,未观察到的 Task 异常会导致整个进程中断。 TaskScheduler.UnobservedTaskException 事件是崩溃前处理异常的最后一个选项(与 UnhandledException 的情况非常相似)。在 .Net 4.5 中,此类异常不再使应用程序崩溃,但事件仍会引发

如果您想在这种情况下使应用程序崩溃(我怀疑您会这样做),您可以设置 <ThrowUnobservedTaskExceptions enabled="true"/>,正如 Yuval 指出的那样。您可以改为使用事件本身来处理异常,这不是最佳的原因有两个:

  1. .Net 决定你的任务的异常只有在任务被垃圾收集时才被观察到,这 可能随时发生 (或者永远不会,如果你不释放对它的所有引用)。在那之前您仍然可以自己处理异常,所以它还没有被观察到。
  2. 您得到了异常,但没有得到任务,如果没有它,可能很难知道问题的真正根源。

结论

确保 await 您的任务在异常发生时进行处理。还可以使用 UnobservedTaskException 作为万一你错过了任务。