我如何(优雅地)从内部关闭工作人员服务?

Sör*_*lau 13 c# asp.net .net-core

我正在使用 .NET Core 3.1 辅助服务模板来构建 Windows 服务。

我认为基本流程应该在 内处理ExecuteAsync,大致如下:

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            while (!stoppingToken.IsCancellationRequested)
            {
                try
                {
                    _Logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);

                    await SomeMethodThatDoesTheWork(stoppingToken);
                }
                catch (Exception ex)
                {
                    _Logger.LogError(ex, "Global exception occurred. Will resume in a moment.");
                }

                await Task.Delay(TimeSpan.FromSeconds(10), stoppingToken);
            }
        }
Run Code Online (Sandbox Code Playgroud)

我正在尝试从进程中正确发出我希望应用程序关闭的信号。

停止服务时,我假设StopAsync()被调用。这似乎工作正常。所以我认为await StopAsync()会成功,但之后,ExecuteAsync仍然继续运行(所以我猜StopAsync不会要求取消,你不应该自己调用它)。

所以我用另一个布尔值修改了我的循环:

            while (!stoppingToken.IsCancellationRequested && !_ShuttingDown)

Run Code Online (Sandbox Code Playgroud)

这确实退出循环,并且永远不会ExecuteAsync再次进入。但是,该应用程序只是继续运行。根据调试器,它只是停留在host.Run().

我如何向应用程序主机发出我想要关闭的信号?

Ste*_*ary 35

在 ASP.NET Core 中,后台服务独立于应用程序。例如,服务完成但应用程序继续执行是可能的。如果您希望您的应用程序在后台服务完成时退出,那么您需要自己连接它。

您可以注入IHostApplicationLifetime您的服务,然后调用IHostApplicationLifetime.StopApplication. 像这样的东西:

public sealed class MyService : BackgroundService
{
  private readonly IHostApplicationLifetime _hostApplicationLifetime;
  private readonly ILogger<MyService> _logger;

  public MyService(IHostApplicationLifetime hostApplicationLifetime, ILogger<MyService> logger)
  {
    _hostApplicationLifetime = hostApplicationLifetime;
    _logger = logger;
  }

  protected override async Task ExecuteAsync(CancellationToken stoppingToken)
  {
    try
    {
      while (!stoppingToken.IsCancellationRequested)
      {
        try
        {
          _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
          await SomeMethodThatDoesTheWork(stoppingToken);
        }
        catch (Exception ex)
        {
          _logger.LogError(ex, "Global exception occurred. Will resume in a moment.");
        }

        await Task.Delay(TimeSpan.FromSeconds(10), stoppingToken);
      }
    }
    finally
    {
      _logger.LogCritical("Exiting application...");
      _hostApplicationLifetime.StopApplication();
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

  • “您可以将 IHostApplicationLifetime 注入到您的服务中,然后调用 IHostApplicationLifetime.StopApplication。” 宾果,我想这就是我一直在寻找的! (2认同)