从Task.ContinueWith抛出异常到主线程

时间:2018-08-09 09:18:06

标签: c# asp.net asp.net-core multitasking

在ASP.NET Core控制器中->我试图从Task中抛出一个异常(以记录该异常),但是我不明白为什么全局控制器异常过滤器无法捕获该异常。 / p>

public IActionResult MyAction()
{
    Task task = GetMyTask();

    SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());

    task.ContinueWith(t =>
        {
            if (t.IsFaulted && t.Exception != null && t.Exception.InnerException != null)
            {
                throw t.Exception.InnerException; // Code reached, but this exception is NOT handled by the controller global error handler
            }
        }, cancellationToken: CancellationToken.None, continuationOptions: TaskContinuationOptions.OnlyOnFaulted, scheduler: TaskScheduler.FromCurrentSynchronizationContext() );

    throw new Exception("This exception is handled by the controller global error handler");
    return Ok();
}

我不想使用await,因为此任务是一劳永逸的。

1 个答案:

答案 0 :(得分:1)

await关键字几乎完成了一项工作:它保留对代码的处理,直到任务返回为止。它还可以解包任务,但这只是为了方便。

由于您此处未使用await,这意味着调用代码继续运行,并且您的响应在任务仍完成时返回。您实际上是将其从请求管道上下文中删除,这意味着您无法捕获它引发的任何异常-着火了,忘了,重点是忘记

这与在“后台”执行操作不同。如果您要处理请求之外的一些长时间运行的过程,则解决方案是安排它,并由IHostedService之类的东西或像Hangfire这样的库进行处理。这样,您的请求可以继续返回,但是现在您正在受监视的上下文中进行工作,在这里您可以执行诸如引发异常之类的事情。但是,此时您需要格外小心,因为异常仍然不会出现在全局异常处理程序中,因为没有任何请求在进行中。相反,您需要捕获异常,然后通过诸如SignalR(websockets)之类的方式通知客户端,将其记录下来。这也将使您可以潜在地监视流程的状态,并向其报告用户(再次通过SignalR)进行进度和完成进度。仅在不等待任务的情况下运行任务,这是不可能的。