.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看看效果吧

写在最后
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)


.NET Core 实现后台任务(定时任务)BackgroundService(二)的更多相关文章
- ASP.NET Core 使用 Hangfire 定时任务
定时任务组件,除了 Hangfire 外,还有一个 Quarz.NET,不过 Hangfire .NET Core 支持的会更好些. ASP.NET Core 使用 Hangfire 很简单,首先,N ...
- Core开发-后台任务利器Hangfire使用
Core开发-后台任务利器Hangfire使用 ASP.NET Core开发系列之后台任务利器Hangfire 使用. Hangfire 是一款强大的.NET开源后台任务利器,无需Windows服务/ ...
- ASP.NET Core中使用IOC三部曲(二.采用Autofac来替换IOC容器,并实现属性注入)
前言 本文主要是详解一下在ASP.NET Core中,自带的IOC容器相关的使用方式和注入类型的生命周期. 这里就不详细的赘述IOC是什么 以及DI是什么了.. emm..不懂的可以自行百度. 目录 ...
- ASP.NET Core 基于JWT的认证(二)
ASP.NET Core 基于JWT的认证(二) 上一节我们对 Jwt 的一些基础知识进行了一个简单的介绍,这一节我们将详细的讲解,本次我们将详细的介绍一下 Jwt在 .Net Core 上的实际运用 ...
- .net core 的图片处理及二维码的生成及解析
写代码这事,掐指算来已经十有余年. 从html到css到javascript到vbscript到c#,从兴趣到职业,生活总是失落与惊喜并存. 绝大部分时候,出发并不是因为知道该到哪里去,只是知道不能再 ...
- C# 动态创建SQL数据库(二) 在.net core web项目中生成二维码 后台Post/Get 请求接口 方式 WebForm 页面ajax 请求后台页面 方法 实现输入框小数多 自动进位展示,编辑时实际值不变 快速掌握Gif动态图实现代码 C#处理和对接HTTP接口请求
C# 动态创建SQL数据库(二) 使用Entity Framework 创建数据库与表 前面文章有说到使用SQL语句动态创建数据库与数据表,这次直接使用Entriy Framwork 的ORM对象关 ...
- 一张图搞定OAuth2.0 在Office应用中打开WPF窗体并且让子窗体显示在Office应用上 彻底关闭Excle进程的几个方法 (七)Net Core项目使用Controller之二
一张图搞定OAuth2.0 目录 1.引言 2.OAuth2.0是什么 3.OAuth2.0怎么写 回到顶部 1.引言 本篇文章是介绍OAuth2.0中最经典最常用的一种授权模式:授权码模式 非常 ...
- 使用.NET Core创建Windows服务(二) - 使用Topshelf方式
原文:Creating Windows Services In .NET Core – Part 2 – The "Topshelf" Way 作者:Dotnet Core Tut ...
- 深入理解.NET Core的基元(二) - 共享框架
原文:Deep-dive into .NET Core primitives, part 2: the shared framework 作者:Nate McMaster 译文:深入理解.NET Co ...
- 深入理解.NET Core的基元(二)
原文:Deep-dive into .NET Core primitives, part 2: the shared framework作者:Nate McMaster译文:深入理解.NET Core ...
随机推荐
- 携程开源分布式配置系统Apollo服务端是如何实时更新配置的?
引言 前面有写过一篇<分布式配置中心apollo是如何实时感知配置被修改>,也就是客户端client是如何知道配置被修改了,有不少读者私信我你既然说了client端是如何感知的,那服务端又 ...
- spring-data-jpa操作数据库
1.spring-data-jpa是spring对hibernate的整合 2.spring boot工程在实体类添加注解.添加两个依赖.写配置文件,可以自动生成数据库表 实体类: @Entity / ...
- Django-----cookie&session
cookie 保存在用户浏览器端的一个键值对(别人给的凭证) 服务端可以向用户浏览器写cookie 客户端每次发请求会携带cookie去(放在请求头里面) 淘宝的cookie 京东的cookie(h ...
- 《Streaming Systems》第一章: Streaming 101
数据的价值在其产生之后,将随着时间的流逝逐渐降低.因此,为了获得最大化的数据价值,尽可能实时.快速地处理新产生的数据就显得尤为重要.实时数据处理将在越来越多的场景中体现出更大的价值所在 -- 实时即未 ...
- 实践GoF的23种设计模式:建造者模式
摘要:针对这种对象成员较多,创建对象逻辑较为繁琐的场景,非常适合使用建造者模式来进行优化. 本文分享自华为云社区<[Go实现]实践GoF的23种设计模式:建造者模式>,作者: 元闰子. 简 ...
- 如何使用Python实现图像融合及加法运算?
摘要:本篇文章主要讲解Python调用OpenCV实现图像融合及加法运算,包括三部分知识:图像融合.图像加法运算.图像类型转换. 本文分享自华为云社区<[Python图像处理] 五.图像融合.加 ...
- 【多线程】线程礼让 Thread.yield()
线程礼让 Thread.yield() 礼让线程,让当前正在执行的线程暂停,但不阻塞 : 将线程从运行状态转为就绪状态 : 让cpu重新调度,礼让不一定成功!看CPU心情. 代码示例: /** * @ ...
- CentOS7软件环境
一.软件环境 1.1 centos7 [root@centos7 ~]# cat /etc/redhat-release CentOS Linux release 7.4.1708 (Core) [r ...
- .net6.0 初探
概述:大概的了解一下 dotnet 6.0 建立 MVC web项目的过程以及程序调用 结合 EF 框架进行简单 的CRUD 1.选择创建 MVC 的Web项目 2.框架类型选择 6.0 3. 6 ...
- Cabloy-CMS中区块的开发与效果
关于区块 Cabloy-CMS引入了区块的概念,通过区块可以快速向文章添加各种类型的内容,比如:插入一个地图子页面.插入一首音乐,等等 Cabloy-CMS中的区块可以类比于Wordpress古腾堡编 ...