原文连接: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(二)的更多相关文章

  1. ASP.NET Core 使用 Hangfire 定时任务

    定时任务组件,除了 Hangfire 外,还有一个 Quarz.NET,不过 Hangfire .NET Core 支持的会更好些. ASP.NET Core 使用 Hangfire 很简单,首先,N ...

  2. Core开发-后台任务利器Hangfire使用

    Core开发-后台任务利器Hangfire使用 ASP.NET Core开发系列之后台任务利器Hangfire 使用. Hangfire 是一款强大的.NET开源后台任务利器,无需Windows服务/ ...

  3. ASP.NET Core中使用IOC三部曲(二.采用Autofac来替换IOC容器,并实现属性注入)

    前言 本文主要是详解一下在ASP.NET Core中,自带的IOC容器相关的使用方式和注入类型的生命周期. 这里就不详细的赘述IOC是什么 以及DI是什么了.. emm..不懂的可以自行百度. 目录 ...

  4. ASP.NET Core 基于JWT的认证(二)

    ASP.NET Core 基于JWT的认证(二) 上一节我们对 Jwt 的一些基础知识进行了一个简单的介绍,这一节我们将详细的讲解,本次我们将详细的介绍一下 Jwt在 .Net Core 上的实际运用 ...

  5. .net core 的图片处理及二维码的生成及解析

    写代码这事,掐指算来已经十有余年. 从html到css到javascript到vbscript到c#,从兴趣到职业,生活总是失落与惊喜并存. 绝大部分时候,出发并不是因为知道该到哪里去,只是知道不能再 ...

  6. C# 动态创建SQL数据库(二) 在.net core web项目中生成二维码 后台Post/Get 请求接口 方式 WebForm 页面ajax 请求后台页面 方法 实现输入框小数多 自动进位展示,编辑时实际值不变 快速掌握Gif动态图实现代码 C#处理和对接HTTP接口请求

    C# 动态创建SQL数据库(二) 使用Entity Framework  创建数据库与表 前面文章有说到使用SQL语句动态创建数据库与数据表,这次直接使用Entriy Framwork 的ORM对象关 ...

  7. 一张图搞定OAuth2.0 在Office应用中打开WPF窗体并且让子窗体显示在Office应用上 彻底关闭Excle进程的几个方法 (七)Net Core项目使用Controller之二

    一张图搞定OAuth2.0   目录 1.引言 2.OAuth2.0是什么 3.OAuth2.0怎么写 回到顶部 1.引言 本篇文章是介绍OAuth2.0中最经典最常用的一种授权模式:授权码模式 非常 ...

  8. 使用.NET Core创建Windows服务(二) - 使用Topshelf方式

    原文:Creating Windows Services In .NET Core – Part 2 – The "Topshelf" Way 作者:Dotnet Core Tut ...

  9. 深入理解.NET Core的基元(二) - 共享框架

    原文:Deep-dive into .NET Core primitives, part 2: the shared framework 作者:Nate McMaster 译文:深入理解.NET Co ...

  10. 深入理解.NET Core的基元(二)

    原文:Deep-dive into .NET Core primitives, part 2: the shared framework作者:Nate McMaster译文:深入理解.NET Core ...

随机推荐

  1. OA办公软件篇(三)—审批流

    背景 作用 迭代历程 具体实现 写在最后   背景 在前面两篇文章中,我们分别讲了组织架构和权限管理,今天我们来讲一个跟组织架构关系比较密切的功能-审批流. 审批流,通俗来说就是一个完整的审批流程,是 ...

  2. Windows下查找各类游戏存档路径

    我算是个比较爱打单机游戏的人,同时也是个半吊子的编程爱好者,有的时候会去干一些修改存档的事儿.不过这篇博文不讲存档修改技术,只讲第一步:去哪找存档? 目标:在windows10系统下搜索到游戏的存档路 ...

  3. Linux系统inodes资源耗尽问题

    1 inodes介绍 Linux系统下文件数据储存在"块"中,文件的元信息,例如文件的创建者.文件的创建日期.文件的大小等.这种储存文件元信息的区域就叫做inode,中文译名为&q ...

  4. MySQL双主双从配置

    双主双从结构图 Master1配置 server-id=1 #开启binlog日志 log-bin=mysql-bin #忽略的库 binlog-ignore-db=mysql #复制的库 binlo ...

  5. 使用Spring MVC开发RESTful API(续)

    使用多线程提高REST服务性能 异步处理REST服务,提高服务器吞吐量 使用Runnable异步处理Rest服务 AsyncController.java @RestController @GetMa ...

  6. 分布式下Session一致性架构举例

    一.问题及方案 见这篇文章:分布式下Session一致性问题 二.分布式环境搭建: 系统环境 [root@centos7 ~]# cat /etc/redhat-release CentOS Linu ...

  7. linux篇-CentOS7搭建NTP服务器

    1查看服务器.客户端操作系统版本 2查看服务器是否安装ntp 3如果没有安装 4安装完成后重新查看服务器是否安装ntp 5查看ntp服务器状态 6修改配置文件 注释 #server 0.centos. ...

  8. 好客租房23-react组件的两种创建方式(抽离为独立js)

    2.3抽离为单独组件 组件作为一个单独的个体,一般把每个组件放在单独的js中文件中 1创建hello.js 2在hello.js中导入React 3创建组件(函数或者类) hello.js子组件 // ...

  9. 基于C++11的数据库连接池实现

    0.注意 该篇文章为了让大家尽快看到效果,代码放置比较靠前,看代码前务必看下第4部分的基础知识. 1.数据库连接池 1.1 是什么? 数据库连接池负责分配.管理和释放数据库连接,属于池化机制的一种,类 ...

  10. .Net分表分库动态化处理

    介绍 本期主角:ShardingCore 一款ef-core下高性能.轻量级针对分表分库读写分离的解决方案,具有零依赖.零学习成本.零业务代码入侵 背景 最近有个小伙伴来问我,分表下他有一批数据,这个 ...