![](/style/images/good.png)
![](/style/images/bad.png)
.NET Core 实现后台任务(定时任务)BackgroundService(二) - 一事冇诚
source link: https://www.cnblogs.com/ysmc/p/16468560.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
.NET Core 实现后台任务(定时任务)BackgroundService(二)
原文连接:https://www.cnblogs.com/ysmc/p/16468560.html
在上一篇文档中说到使用 IHostedService 接口实现定时任务 传送门,其中,有小伙伴就问到,为什么不使用 BackgroundService,我个人觉得使用什么技术,应该取决于需求,代码只是一种工具,用得顺手对于编码人员来说,我个人感觉还是非常重要的;正好也说到了 BackgroundService,那这一篇文档就简单说一下它吧。
首先我们看一下官方的说明,学习代码一定要看官方的文档,尽管有时候会有点晦涩难懂,但肯定是最正确的:
BackgroundService 基类
BackgroundService 是用于实现长时间运行的 IHostedService 的基类。
调用 ExecuteAsync(CancellationToken) 来运行后台服务。 实现返回一个 Task,其表示后台服务的整个生存期。
在 ExecuteAsync 变为异步(例如通过调用 await
)之前,不会启动任何其他服务。 避免在 ExecuteAsync
中执行长时间的阻塞初始化工作。
StopAsync(CancellationToken) 中的主机块等待完成 ExecuteAsync
。
调用 IHostedService.StopAsync 时,将触发取消令牌。 当激发取消令牌以便正常关闭服务时,ExecuteAsync
的实现应立即完成。 否则,服务将在关闭超时后不正常关闭。
StartAsync
应仅限于短期任务,因为托管服务是按顺序运行的,在 StartAsync
运行完成之前不会启动其他服务。 长期任务应放置在 ExecuteAsync
中。
针对第一点“BackgroundService 是用于实现长时间运行的 IHostedService 的基类”,我们先看看 BackgroundService 的源码:
1 public abstract class BackgroundService : IHostedService, IDisposable 2 { 3 private Task _executingTask; 4 private readonly CancellationTokenSource _stoppingCts = new CancellationTokenSource(); 5 6 /// <summary> 7 /// This method is called when the <see cref="IHostedService"/> starts. The implementation should return a task that represents 8 /// the lifetime of the long running operation(s) being performed. 9 /// /// </summary> 10 /// <param name="stoppingToken">Triggered when <see cref="IHostedService.StopAsync(CancellationToken)"/> is called.</param> 11 /// <returns>A <see cref="Task"/> that represents the long running operations.</returns> 12 protected abstract Task ExecuteAsync(CancellationToken stoppingToken); 13 14 /// <summary> 15 /// Triggered when the application host is ready to start the service. 16 /// </summary> 17 /// <param name="cancellationToken">Indicates that the start process has been aborted.</param> 18 public virtual Task StartAsync(CancellationToken cancellationToken) 19 { 20 // Store the task we're executing 21 _executingTask = ExecuteAsync(_stoppingCts.Token); 22 23 // If the task is completed then return it, this will bubble cancellation and failure to the caller 24 if (_executingTask.IsCompleted) 25 { 26 return _executingTask; 27 } 28 29 // Otherwise it's running 30 return Task.CompletedTask; 31 } 32 33 /// <summary> 34 /// Triggered when the application host is performing a graceful shutdown. 35 /// </summary> 36 /// <param name="cancellationToken">Indicates that the shutdown process should no longer be graceful.</param> 37 public virtual async Task StopAsync(CancellationToken cancellationToken) 38 { 39 // Stop called without start 40 if (_executingTask == null) 41 { 42 return; 43 } 44 45 try 46 { 47 // Signal cancellation to the executing method 48 _stoppingCts.Cancel(); 49 } 50 finally 51 { 52 // Wait until the task completes or the stop token triggers 53 await Task.WhenAny(_executingTask, Task.Delay(Timeout.Infinite, cancellationToken)); 54 } 55 56 } 57 58 public virtual void Dispose() 59 { 60 _stoppingCts.Cancel(); 61 } 62 }
以上代码很好的解答了小伙伴提出“为什么不使用 BackgroundService”的问题,在上一篇文章中,评论区的一位大佬也很好的回答了这位小伙伴的问题,我这里引用下这位大佬的原话:“BackgroundService 是 IHostedService的一个简单实现,内部IHostedService 的StartAsync调用了ExecuteAsync”,本质上就是使用了 IHostedService;
让我们回到正题,怎么用 BackgroundService 实现定时任务呢,老规矩,上代码:
首先,创建一个服务接口,定义需要实现的任务,以及对应的实现,如果需要执行异步方法,记得加上 await,不然任务将不会等待执行结果,直接进行下一个任务。
1 public class TaskWorkService : ITaskWorkService 2 { 3 public async Task TaskWorkAsync(CancellationToken stoppingToken) 4 { 5 while (!stoppingToken.IsCancellationRequested) 6 { 7 //执行任务 8 Console.WriteLine($"{DateTime.Now}"); 9 10 //周期性任务,于上次任务执行完成后,等待5秒,执行下一次任务 11 await Task.Delay(500); 12 } 13 } 14 }
builder.Services.AddScoped<ITaskWorkService, TaskWorkService>();
创建后台服务类,继承基类 BackgroundService,这里需要注意的是,要在 BackgroundService 中使用有作用域的服务,请创建作用域, 默认情况下,不会为托管服务创建作用域,得自己管理服务的生命周期,切记!于构造函数中注入 IServiceProvider即可。
1 public class BackgroundServiceDemo : BackgroundService 2 { 3 private readonly IServiceProvider _services; 4 5 public BackgroundServiceDemo(IServiceProvider services) 6 { 7 _services = services; 8 } 9 10 protected override async Task ExecuteAsync(CancellationToken stoppingToken) 11 { 12 using var scope = _services.CreateScope(); 13 14 var taskWorkService = scope.ServiceProvider.GetRequiredService<ITaskWorkService>(); 15 16 await taskWorkService.TaskWorkAsync(stoppingToken); 17 } 18 }
最后别忘了这个类也是需要注册的,注册方式与 IHostedService 接口的方式一样
builder.Services.AddHostedService<BackgroundServiceDemo>();
大功告成,F5看看效果吧
![1897432-20220713002203062-236964426.gif](https://img2022.cnblogs.com/blog/1897432/202207/1897432-20220713002203062-236964426.gif)
写在最后
Bootstrap Blazor 官网地址:https://www.blazor.zone
希望大佬们看到这篇文章,能给项目点个star支持下,感谢各位!
star流程:
1、访问点击项目链接:BootstrapBlazor
2、点击star,如下图,即可完成star,关注项目不迷路:
另外还有两个GVP项目,大佬们方便的话也点下star呗,非常感谢:
BootstrapAdmin 项目地址:
https://gitee.com/LongbowEnterprise/BootstrapAdmin
SliderCaptcha 项目地址:
https://gitee.com/LongbowEnterprise/SliderCaptcha
交流群(QQ)欢迎加群讨论
BA & Blazor ①(795206915) BA & Blazor ②(675147445)
![1897432-20220403225036952-1976037800.png](https://img2022.cnblogs.com/blog/1897432/202204/1897432-20220403225036952-1976037800.png)
![1897432-20220403225055624-841710730.png](https://img2022.cnblogs.com/blog/1897432/202204/1897432-20220403225055624-841710730.png)
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK