如何在 ASP.net 核心中手动重启 BackgroundService

How to restart manually a BackgroundService in ASP.net core

我创建后台服务:

public class CustomService : BackgroundService
{
    protected override async Task ExecuteAsync(CancellationToken cancellationToken)
    {
        //...
    }
}

我添加到项目中:

public class Startup
{
    //...

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddHostedService<CustomService>();

        //...
    }

    //...
}

如何从另一个 class 中找到 CustomService?
如何重新开始?

为调用 StartAsync 创建一个接口:

public interface ICustomServiceStarter
{
    Task StartAsync(CancellationToken token = default);
}

public class CustomService : BackgroundService, ICustomServiceStarter
{
    //...
    Task ICustomServiceStarter.StartAsync(CancellationToken token = default) => base.StartAsync(token);
    //...
}

将接口注册为单例:

public class Startup
{
    //...
    public void ConfigureServices(IServiceCollection services)
    {
        //...
        services.AddSingleton<ICustomServiceStarter, CustomService>();
    }
    //...
}

并在需要时注入 ICustomServiceStarter

public class MyServiceControllerr : Controller
{
    ICustomServiceStarter _starter;

    public MyServiceController(ICustomServiceStarter starter)
    {
        _starter = starter;
    }

    [HttpPost]
    public async Task<IActionResult> Start()
    {
        await _starter.StartAsync();

        return Ok();
    }
}

当谈到控制器的动作时,使用“await BackgroundService.StartAsync”是 long-running 任务的错误方式。

例如,主要用途可能是请求的超时取决于代理设置。

下面是一个如何使您的 BackgroundService 可重启的示例。

后台服务实现:

public class MyBackgroundService: BackgroundService
{
  private volatile bool _isFinished = false;
  private SemaphoreSlim _semaphore = new SemaphoreSlim(0,1);

  protected override async Task ExecuteAsync(CancellationToken stoppingToken)
  {
    _isFinished = false;
     // DoSomeWork
    _isFinished = true;
    await WaitToRestartTask(stoppingToken);
  }

  private async Task WaitToRestartTask(CancellationToken stoppingToken)
  {
     // wait until _semaphore.Release()
     await _semaphore.WaitAsync(stoppingToken);
     // run again
     await base.StartAsync(stoppingToken);
  }

  public void RestartTask()
  {
     if (!_isFinished)
          throw new InvalidOperationException("Background service is still working");

     // enter from _semaphore.WaitAsync
     _semaphore.Release();
  }  
}

控制器的操作(例如):

public async Task<IActionResult> Restart()
{
    var myBackgroundService= _serviceProvider.GetServices<IHostedService>()
                .OfType<MyBackgroundService>()
                .First();

    try
    {
       myBackgroundService.RestartTask();
       return Ok($"MyBackgroundService was restarted");
    }
    catch (InvalidOperationException exception)
    {
       return BadRequest(exception.Message);
    }
}