不太清楚您是想取消所有服务,甚至是应用程序本身(或至少是主机),还是只想取消单个服务。
停止应用程序
要取消应用程序,请在将强制取消的类中注入 IHostApplicationLifetime 接口,并在需要时调用 StopApplication。如果您想从后台服务本身内部取消,可能是因为没有其他事情可做,那就需要注入。
StopApplication
将告诉主机应用程序需要关闭。主机将调用所有托管服务上的 StopAsync
。由于使用了 BackgroundService
,因此实现将触发传递给 ExecuteAsync
的 cancellationToken
:
public virtual async Task StopAsync(CancellationToken cancellationToken)
{
if (_executeTask == null)
{
return;
}
try
{
_stoppingCts.Cancel();
}
finally
{
await Task.WhenAny(_executeTask, Task.Delay(Timeout.Infinite, cancellationToken)).ConfigureAwait(false);
}
}
您完全不需要改变您当前的代码。唯一需要注意的是,await Task.Delay()
会导致计时器泄漏。最好明确地使用一个 Timer
,并在取消触发时处理它。
例如,如果您想从控制器操作关闭应用程序:
public class MyServiceControllerr:Controller
{
IHostApplicationLifetime _lifetime;
public MyServiceController(IHostApplicationLifetime lifeTime)
{
_lifeTime=lifeTime;
}
[HttpPost]
public IActionResult Stop()
{
_lifeTime.StopApplication();
return Ok();
}
}
停止服务
如果你只想停止这一个服务,你需要一种方法从其他代码中调用它的 StopAsync
方法。有很多种方法可以做到这一点。其中一种方法是将CustomService
注入到调用者中并调用StopAsync
。但这不是一个很好的想法,因为它会暴露服务并将控制器/停止代码与服务耦合起来。测试这个也不容易。
另一种可能性是创建一个接口,专门用于调用 StopAsync
,例如:
public interface ICustomServiceStopper
{
Task StopAsync(CancellationToken token=default);
}
public class CustomService : BackgroundService,ICustomServiceStopper
{
...
Task ICustomServiceStopper.StopAsync(CancellationToken token=default)=>base.StopAsync(token);
}
将该接口注册为单例:
services.AddSingleton<ICustomServiceStopper,CustomService>()
在需要时注入ICustomServiceStopper
:
public class MyServiceControllerr:Controller
{
ICustomServiceStopper _stopper;
public MyServiceController(ICustomServiceStopper stopper)
{
_stopper=stopper;
}
[HttpPost]
public async Task<IActionResult> Stop()
{
await _stopper.StopAsync();
return Ok();
}
}
.GetService<IEnumerable<IHostedService>>().OfType<CustomService>().Single().MethodName(....)
。(或注入其他常见服务以指示取消...) - Jeremy LakemanIHostedService
。BackgroundService
就是 一个 IHostedSevice。但是,您所说的手动取消
是什么意思呢?是显式地取消所有后台服务,甚至应用程序本身吗?还是只取消一个服务而让其他服务继续运行? - Panagiotis KanavosBackgroundService
实例,您需要像上面我的示例那样做一些事情。如果您以另一种方式注册服务,您将拥有多个实例。 - Jeremy Lakeman