首页 > 解决方案 > UseExceptionHandler 不会捕获任务异常?

问题描述

我创建了一个简单的 webapi .net core 3.1 应用程序。

我想捕获所有未处理的异常。所以我根据文档放置了这段代码:

app.UseExceptionHandler(c => c.Run(async context =>
{
    var exception = context.Features
        .Get<IExceptionHandlerPathFeature>()
        .Error;
    var response = new { error = exception.Message };
    log.LogDebug(exception.Message);
}));

这是我的行动:

[HttpGet]
public IActionResult Get()
{
    throw new Exception("this is a test");
}

当这段代码运行时,我确实看到它UseExceptionHandler正在工作。

但是当我在操作中的代码是:

[HttpGet]
public IActionResult Get()
{
    Task.Run(async () =>
    {
        await Task.Delay(4000);
        throw new Exception("this is a test");
    });
       
    return Ok();
}

然后UseExceptionHandler工作

但是 - 以下代码确实捕获了任务的异常:

 AppDomain.CurrentDomain.FirstChanceException += (sender, eventArgs) =>
 {
     Debug.WriteLine(eventArgs.Exception.ToString());
 };  

问题:

注意,我确实禁用了app.UseDeveloperExceptionPage();

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

解决方案


回答你的问题。

为什么 UseExceptionHandler 无法识别任务异常?

正如评论中已经建议的那样,您不能使用UseExceptionHandler来捕获在非等待任务中启动的异常。UseExceptionHandler将您的请求包装在 ASP.NET Core 中间件中。一旦动作返回OK到客户端,中间件就不再能够捕获从动作内启动的任务中发生的任何异常。

如何捕获所有类型的异常?我应该只依赖 AppDomain.CurrentDomain.FirstChanceException 吗?

如果您愿意,您可以全局捕获异常并以这种方式记录它们。但我不建议你这样做。您需要实现此事件的唯一原因是您正在 Web 请求中启动任务/线程。您无法知道这些任务是否一直在运行(应用程序重新启动、回收等)。如果您希望使用 ASP.NET Core 启动后台任务,则应使用 Worker Services,这是执行此操作的预期方式:

.ConfigureServices((hostContext, services) =>
{
    services.AddHostedService<MyWorker>();
});
public class MyWorker : BackgroundService
{
    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            try
            {
                // Do work
            }
            catch (Exception e)
            {
                // Log it?
            }

            await Task.Delay(TimeSpan.FromMinutes(5), stoppingToken);
        }
    }
}

推荐阅读