在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
,因为此任务是一劳永逸的。
答案 0 :(得分:1)
await
关键字几乎完成了一项工作:它保留对代码的处理,直到任务返回为止。它还可以解包任务,但这只是为了方便。
由于您此处未使用await
,这意味着调用代码继续运行,并且您的响应在任务仍完成时返回。您实际上是将其从请求管道上下文中删除,这意味着您无法捕获它引发的任何异常-着火了,忘了,重点是忘记。
这与在“后台”执行操作不同。如果您要处理请求之外的一些长时间运行的过程,则解决方案是安排它,并由IHostedService
之类的东西或像Hangfire这样的库进行处理。这样,您的请求可以继续返回,但是现在您正在受监视的上下文中进行工作,在这里您可以执行诸如引发异常之类的事情。但是,此时您需要格外小心,因为异常仍然不会出现在全局异常处理程序中,因为没有任何请求在进行中。相反,您需要捕获异常,然后通过诸如SignalR(websockets)之类的方式通知客户端,将其记录下来。这也将使您可以潜在地监视流程的状态,并向其报告用户(再次通过SignalR)进行进度和完成进度。仅在不等待任务的情况下运行任务,这是不可能的。