在 ASP.NET Core 中,后台任务做为托管服务实现.托管服务是一个类,并且必须实现 IHostedService 接口,该接口定义了两个方法:html
托管服务在应用启动时激活一次,在应用关闭时正常关闭.实现 IDisposable 时,可在处置服务容器时处理资源.若是在执行后台任务期间引起错误,即便未调用 StopAsync ,也应调用 Dispose.缓存
示例一:计时的后台任务服务器
public class TimedHostedService : IHostedService, IDisposable { private readonly ILogger _logger; private Timer _timer; public TimedHostedService(ILogger<TimedHostedService> logger) { _logger = logger; } public Task StartAsync(CancellationToken cancellationToken) { _logger.LogInformation("Timed Background Service is starting." + DateTime.Now); _timer = new Timer(DoWork, null, TimeSpan.Zero, TimeSpan.FromSeconds(5));//当即执行一次,每5秒执行一次 return Task.CompletedTask; } private void DoWork(object state) { _logger.LogInformation("Timed Background Service is working." + DateTime.Now); } public Task StopAsync(CancellationToken cancellationToken) { _logger.LogInformation("Timed Background Service is stopping." + DateTime.Now); _timer?.Change(Timeout.Infinite, 0);//再也不执行 return Task.CompletedTask; } public void Dispose() { _timer?.Dispose(); } }
注册该后台任务:网络
public void ConfigureServices(IServiceCollection services) { services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); services.AddHostedService<TimedHostedService>(); }
在控制台启动该项目,期间用 ctrl+C 结束应用.async
其实官方帮咱们封装了一个类来简化上述代码:ide
/// <summary> /// Base class for implementing a long running <see cref="T:Microsoft.Extensions.Hosting.IHostedService" />. /// </summary> public abstract class BackgroundService : IHostedService, IDisposable
所以上述代码能够修改为:测试
public class MyBackGroundTask : BackgroundService { private readonly ILogger _logger; private Timer _timer; public MyBackGroundTask(ILogger<MyBackGroundTask> logger) { _logger = logger; } protected override async Task ExecuteAsync(CancellationToken stoppingToken) { _logger.LogInformation($" MyBackGroundTask is starting. {DateTime.Now}"); while (!stoppingToken.IsCancellationRequested) { _logger.LogInformation($" MyBackGroundTask is working. {DateTime.Now}"); await Task.Delay(5000, stoppingToken); } _logger.LogInformation($" MyBackGroundTask is stopping. {DateTime.Now}"); } }
可是,我发现 网站
_logger.LogInformation($" MyBackGroundTask is stopping. {DateTime.Now}");
这句代码始终不执行.不知道是哪里没搞对.但愿大神能帮个忙..
示例二:在后台任务中使用有做用域的服务ui
要使用有做用域的服务,须要先建立一个做用域.默认状况下,不会为托管服务建立做用域.spa
public interface IScopedProcessingService { void DoWork(); } public class ScopedProcessingService : IScopedProcessingService { private readonly ILogger _logger; public ScopedProcessingService(ILogger<ScopedProcessingService> logger) { _logger = logger; } public void DoWork() { _logger.LogInformation($"Scoped Processing Service is working. {DateTime.Now}"); } }
public class ConsumeScopedServiceHostedService : IHostedService { private readonly ILogger _logger; public IServiceProvider Services { get; } public ConsumeScopedServiceHostedService(IServiceProvider services, ILogger<ConsumeScopedServiceHostedService> logger) { Services = services; _logger = logger; } public Task StartAsync(CancellationToken cancellationToken) { _logger.LogInformation($"Consume Scoped Service Hosted Service is starting. {DateTime.Now}"); DoWork(); return Task.CompletedTask; } private void DoWork() { _logger.LogInformation($"Consume Scoped Service Hosted Service is working. {DateTime.Now}"); using (IServiceScope scope = Services.CreateScope())//建立一个做用域. { IScopedProcessingService scopedProcessingService = scope.ServiceProvider.GetRequiredService<IScopedProcessingService>(); scopedProcessingService.DoWork(); } } public Task StopAsync(CancellationToken cancellationToken) { _logger.LogInformation($"Consume Scoped Service Hosted Service is stopping. {DateTime.Now}"); return Task.CompletedTask; } }
可是我真的没搞懂官方这个例子的做用.由于托管服务只会激活一次,有做用域又有什么价值呢?但愿哪位大哥能解答一下.
下面的在摘自网络:https://www.cnblogs.com/FlyLolo/p/ASPNETCore2_11.html
经测试:
1. 当IIS上部署的项目启动后,后台任务随之启动,任务执行相应的log正常输出。
2. 手动回收对应的应用程序池,任务执行相应的log输出中止。
3. 从新请求该网站,后台任务随之启动,任务执行相应的log从新开始输出。
因此不建议在这样的后台任务中作一些须要固定定时执行的业务处理类的操做,但对于缓存刷新类的操做仍是能够的,由于当应用程序池回收后再次运行的时候,后台任务会随着启动。