集中异步任务的异常

Centralizing exceptions from asynchronous tasks

我在我的 MVC 应用程序中实现了一个自定义 HandleErrorAttribute,它以某种方式集中并捕获应用程序中发生的所有异常一直非常有效。

public class CustomHandleErrorAttribute : HandleErrorAttribute
{
    public override void OnException(ExceptionContext filterContext)
    {
        ....
    }
}

问题是:我已经开始执行一些异步任务,比如这个:

Task.Factory.StartNew(() => DoSomethingAsync());

并意识到我的 CustomHandleErrorAttribute 没有拦截那些方法中发生的异常:在这种情况下,如果 DomeSomethingAsync() 方法内部发生异常,那么我的 HandleErrorAttribute不会抓住它; Global.asax 也不会。

什么是集中异步任务中发生的异常的好实现?我不想在每个方法中都实现一个简单的 try/catch 块:我想用某种捕获它们的处理程序来计算。

一个好方法是不使用 Task.Factory.StartNew,尤其是不使用异步方法。

只需直接调用异步方法并等待返回的任务即可。该任务中的异常将通过与所有其他异常相同的机制重新抛出和处理:

await DoSomethingAsync();

Task.Factory.StartNew 对于将工作卸载到 ThreadPool 线程很有用,但是您已经在 ThreadPool 线程上,因此不需要这样做。

如果您想放弃该任务,您应该意识到没有任何东西可以保证它会继续 运行。应用程序池可以在任务 运行 时回收,因为没有任何东西在等待它。

如果你想在 asp.net 中做 "fire and forget" 你应该使用像 HangFire 这样的东西(更多在 Fire and Forget on ASP.NET 中)


在 asp.net 之外的世界中,您可以使用 ContinueWithTaskContinuationOptions.OnlyOnFaulted 简单地添加一个处理程序作为延续,以确保它仅在出现异常时运行,例如扩展方法:

public static void HandleExceptions(this Task task)
{
    task.ContinueWith(
        faultedTask => HandleException(faultedTask.Exception),
        TaskContinuationOptions.OnlyOnFaulted);
}

并像这样使用它:

DoSomethingAsync().HandleExceptions();