try catch中无法获取异常

ANK*_*ANK 1 .net c# exception .net-core worker-service

我的 Program.cs 中的 .net core 3.1 有一个工作人员服务,我有以下代码

public static void Main(string[] args)
{
    try
    {
        CreateHostBuilder(args).Build().Run();
    }
    catch(Exception ex)
    {
        Handler(ex);
    }
}
Run Code Online (Sandbox Code Playgroud)

还有一个工人阶级如下

public class Worker : BackgroundService
{ 
  protected override async Task ExecuteAsync(CancellationToken Token)
  {
    
    do
    { 
     if(condition)
     {
      await _test.GetData();
     }
     await Task.Delay(500,Token);
    }
    while (!Token.IsCancellationRequested);

  }
 }
Run Code Online (Sandbox Code Playgroud)

如果 Task.Delay 首先执行,然后第二次迭代的 GetData() 方法中发生任何异常,则 Main 方法中的 try catch 不会捕获该异常。我怎样才能在我的主要方法中捕获这些异常?

Enr*_*one 5

这是预期的行为。

文件中的 catch 块Program.cs仅处理构建和启动 .NET core 通用主机时引发的异常。就这样。catch 块不会处理注册的托管服务在执行期间抛出的异常。

如果您检查基类的源代码,BackgroundService您就会明白为什么后台服务抛出的异常会丢失。

在这一行,您会看到调用了您的实现ExecuteAsync,并且生成的任务存储在_executeTask字段内。

您的重写ExecuteAsync是一个async函数。当函数内部存在未处理的异常时async,运行时会捕获该异常并将其放置在返回的Task. Task当等待或调用类似 api时,将抛出异常(保留其原始堆栈跟踪)Task.Wait()
请注意,_executeTask不会等待任务,并且执行线程不会尝试通过调用该Task.Wait()方法来同步等待任务完成。因此,没有机会观察由此产生的异常Task

只有一种可能观察到来自您的实现的异常ExecuteAsync。如果在第一条指令之前发生异常,则方法执行将同步完成,并且返回的 Task 属性将设置 true ,其属性将为。在这种情况下,任务将返回到调用代码(参见这一)。awaitIsCompletedStatusFaulted_executeTask

调用代码基本上是启动 .NET Core 通用主机的代码,它将返回错误的任务,并通过等待任务本身来检测启动后台服务时发生的错误。此时,来自该ExecuteAsync方法的异常将被重新抛出,并且 Program.cs 中的 catch 块将处理该异常。

ExecuteAsync 如果在第一个等待指令之后发生任何异常,.NET Core 通用主机将无法观察异常本身。这些异常将导致静默失败。您可以通过阅读这篇精彩的博客文章找到更多详细信息。

正如对您的问题的评论所指出的,这种行为在 .NET 6 中已更改,您可以在此处阅读。简而言之,.NET 6 中的默认行为是记录来自后台服务的任何未处理的异常并停止主机,以便您意识到问题,并且有机会修复代码并调查它抛出的原因例外情况。