大家好,我是张飞洪,感谢您的阅读,我会不定期和你分享学习心得,希望我的文章能成为你成长路上的垫脚石,让我们一起精进。

本章是《定制ASP NET 6.0框架系列文章》的第七篇。本文内容和定制无关,主要是关于创建后台服务,用于异步运行任务的功能,我们会使用此功能定期从远程服务获取数据。

本文的主题主要包括:

  • IHostedService介绍
  • BackgroundService介绍
  • Worker Service介绍

1 技术要求

为了演示,我们先创建一个ASP.NET Core应用,我们使用控制台(ShellBash)终端,切换到工作目录,执行以下命令,创建一个MVC应用程序:

dotnet new mvc -n HostedServiceSample -o HostedServiceSample

使用Visual Studio双击打开项目文件,你也可以使用VS Code打开项目,并在已打开的控制台中执行以下命令:

cd HostedServiceSample code .

2 IHostedService介绍

托管服务自ASP.NET Core 2.0开始出现,可在应用后台异步运行任务。比如,可以定期获取数据、在后台进行一些计算或进行一些数据清理。甚至,我们还可以使它发送预配置的电子邮件,或者在后台执行任意的逻辑操作。

托管服务必须实现IHostedService接口,如下代码所示:

public class SampleHostedService : IHostedService {     
public Task StartAsync(CancellationToken cancellationToken)     {     }     
public Task StopAsync(CancellationToken cancellationToken)     {     }
}

IHostedService需要实现StartAsync()StopAsync()方法。StartAsync()是实现要执行的逻辑的地方,该方法在应用程序启动后立即执行,并且只执行一次;StopAsync()方法在应用程序停止之前执行。这意味着要我们需要自己实现一个计划服务,实现一个定期执行代码的循环。

要执行IHostedService,还需要在ASP.NET Core依赖注入容器注册作为单例实例:

builder.Services.AddSingleton<IHostedService, SampleHostedService>();

我们再看下面这个示例,用于展示托管服务的工作方式。它会在启动、停止和每2秒向控制台写入一条日志消息:

首先,我们编写类的骨架,并通过DI反转一个ILogger的实例:

namespace HostedServiceSample;
public class SampleHostedService:IHostedService {
private readonly ILogger<SampleHostedService> logger;
public SampleHostedService(ILogger<SampleHostedService> logger) {
this.logger = logger;
}
public Task StartAsync(CancellationToken cancellationToken)
{}
public Task StopAsync(CancellationToken cancellationToken)
{}
}

下一步,实现StopAsync方法。此方法用于需要关闭连接时需要处理的逻辑工作:

public Task StopAsync(CancellationToken cancellationToken)
{
logger.LogInformation("托管服务停止……");
return Task.CompletedTask;
}

实际工作将在StartAsync方法内完成:

public Task StartAsync(CancellationToken cancellationToken) {
logger.LogInformation("托管服务开始……");
return Task.Factory.StartNew(async () => {
while (!cancellationToken.IsCancellationRequested) {
logger.LogInformation($"托管服务执行中 - {DateTime.Now}");
try{
//等待2秒
await Task.Delay(TimeSpan.FromSeconds(2), cancellationToken);
}catch (OperationCanceledException) { }
}
}, cancellationToken);
}

接下来运行并测试一下,效果如下图所示,日志每2秒写入一次控制台。:

dotnet run

3 BackgroundService介绍

BackgroundService类是在ASP.NET Core 3.0中被引入的,它是一个实现IHostedService接口的抽象类,它还提供了一个名为ExecuteAsync的抽象方法,该方法返回一个Task任务。

我们重写一下上面示例的托管服务,先搭建一个骨架类,如下所示:

namespace HostedServiceSample;
public class SampleBackgroundService : BackgroundService {
private readonly ILogger<SampleHostedService> logger;
public SampleBackgroundService(ILogger<SampleHostedService> logger){
this.logger = logger;
}
}

接下来重写StopAsync方法:

public override async Task StopAsync(CancellationToken cancellationToken) {
logger.LogInformation("后台服务停止……");
await Task.CompletedTask;
}

最后,我们重写ExecuteAsync方法:

protected override async Task ExecuteAsync(CancellationToken cancellationToken) {
logger.LogInformation("后台服务启动……");     
await Task.Factory.StartNew(async () =>{         
while(!cancellationToken.IsCancellationRequested) {
logger.LogInformation($"后台服务执行中 - {DateTime.Now}");
try{                 
await Task.Delay(TimeSpan.FromSeconds(2), cancellationToken);             
}catch (OperationCanceledException) {}         
}     
}, cancellationToken);
}

注册也要重写一下,在ASP.NET Core 3.0及更高版本中,ServiceCollection有一个新的扩展方法来注册托管服务或后台工作程序:

builder.Services.AddHostedService<SampleBackgroundService>();

在控制台中调用以下命令启动应用程序测试:

dotnet run

测试结果和上头一样,这里不再累述。

4 Worker Service介绍

Worker Service可以叫执行者或者工作者。

ASP.NET Core 3.0及更高版本中,创建简单的工作者服务变得非常容易,这个服务可以也托管在非Web服务器里。

我们再新建一个项目:

dotnet new worker -n BackgroundServiceSample -o BackgroundServiceSample

我们可以看到,该命令会创建一个带有Program.csWorker.cs的控制台应用程序。Worker.cs包含Worker类,它是从BackgroundService类继承的。在ASP.NET 5.0及更早版本,Program.cs文件看起来与以前版本的很相似,但没WebHostBuilder

public class Program {
public static void Main(string[] args){
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args)=>
Host.CreateDefaultBuilder(args).ConfigureServices((hostContext, services) =>{
services.AddHostedService<Worker>();
});
}

ASP.NET Core 6.0中,Program.cs以与迷你API相同,都被简化掉了。它看起来像这样:

using BackgroundServiceSample;
IHost host = Host.CreateDefaultBuilder(args).ConfigureServices(services =>{
services.AddHostedService<Worker>();
}).Build();
await host.RunAsync();

这里创建IHost并启用依赖注入,我们可以在任何类型的.NET Core应用程序中使用依赖注入,而不仅仅是在ASP.NET Core应用程序。

然后,我们将工作进程添加到服务集合中,这样就可以将服务作为Windows服务或Docker容器中的后台程序运行。

小结

有了上面的抛砖引玉,现在您可以使用IHostedServiceBackgroundService开始做一些更复杂的事情了。

如果后台服务和应用都在同一个进程中运行,会消耗太多的CPU或内存,甚至降低应用的速度。

所以,对于大型的应用程序,建议单独创建一个用于执行后台任务的应用程序中,可以部署在单独的Docker容器里、或者云服务器里。一定要确保它与主应用程序分开。

在下一章中,我们将进入中间件的学习,以及如何使用中间件在请求管道上实现特殊逻辑,感谢您的阅读。

如何使用.NET 6的IHostedService和BackgroundService?的更多相关文章

  1. 谈谈.NET Core中基于Generic Host来实现后台任务

    目录 前言 什么是Generic Host 后台任务示例 控制台形式 消费MQ消息的后台任务 Web形式 部署 IHostedService和BackgroundService的区别 IHostBui ...

  2. .NET Core 中的通用主机和后台服务

    简介 我们在做项目的时候, 往往要处理一些后台的任务. 一般是两种, 一种是不停的运行,比如消息队列的消费者.另一种是定时任务. 在.NET Framework + Windows环境里, 我们一般会 ...

  3. NET Core中基于Generic Host来实现后台任务

    NET Core中基于Generic Host来实现后台任务 https://www.cnblogs.com/catcher1994/p/9961228.html 目录 前言 什么是Generic H ...

  4. ApacheCN Asp.NET 译文集 20211126 更新

    ASP.NET Core2 基础知识 零.前言 一.搭建舞台 二.控制器 三.视图 四.模型 五.验证 六.路由 七.RestBuy 八.添加功能.测试和部署 ASP.NET Core3 和 Angu ...

  5. 玩转ASP.NET 6.0框架-序言

    ASP.NET Core是微软提供的强大的web框架,它有很多潜在的强大而有用的功能. 本专栏的目标是帮助您把框架的隐藏能力最大限度地发挥出来,让您能够按需定制ASP NET Core框架.本专栏提供 ...

  6. .NET Core 实现后台任务(定时任务)Longbow.Tasks 组件(三)

    原文链接:https://www.cnblogs.com/ysmc/p/16512309.html 在上两篇文章中,简单介绍了怎么使用 IHostedService 与 BackgroundServi ...

  7. 在.NET 6.0中使用不同的托管模型

    大家好,我是张飞洪,感谢您的阅读,我会不定期和你分享学习心得,希望我的文章能成为你成长路上的垫脚石,让我们一起精进. 本章是<定制ASP NET 6.0框架系列文章>的第六篇.在本章中,我 ...

  8. .NET Core 中基于 IHostedService 实现后台定时任务

    .NET Core 2.0 引入了 IHostedService ,基于它可以很方便地执行后台任务,.NET Core 2.1 则锦上添花地提供了 IHostedService 的默认实现基类 Bac ...

  9. .net core 基于 IHostedService 实现定时任务

    .net core 基于 IHostedService 实现定时任务 Intro 从 .net core 2.0 开始,开始引入 IHostedService,可以通过 IHostedService ...

随机推荐

  1. Canvas 线性图形(五):多边形

    前言 CanvasRenderingContext2D 没有提供绘制多边形的函数,所以只能由我们自己来实现绘制多边形的函数.以六边形为基础,需要用到三角函数:sin 和 cos. 点 A 坐标 (一) ...

  2. numpy中的np.round()取整的功能和注意

    numpy中的np.round()取整的功能和注意 功能 np.round() 是对浮点数取整的一个函数,一般的形式为 np.round(a, b),其中a为待取整的浮点数,b为保留的小数点的位数 注 ...

  3. 表达式的动态解析和计算,Flee用起来真香

    前言 在很多项目中经常会出现需要动态解析表达式和计算的场景,比如一些自动审核规则,或者是一些变量的值通过维护的公式在运行过程中动态算出:由于场景需求,都需要比较灵活的配置对应的表达式,然后希望在需要的 ...

  4. Vuex的各个模块封装

    一.各个模块的作用: state 用来数据共享数据存储 mutation 用来注册改变数据状态(同步) getters 用来对共享数据进行过滤并计数操作 action 解决异步改变共享数据(异步) 二 ...

  5. Redis系列2:数据持久化提高可用性

    1 介绍 从上一篇的 <深刻理解高性能Redis的本质> 中可以知道, 我们经常在数据库层上加一层缓存(如Redis),来保证数据的访问效率. 这样性能确实也有了大幅度的提升,但是本身Re ...

  6. 021(Keywords Search)(AC自动机)

    题目:http://ybt.ssoier.cn:8088/problem_show.php?pid=1479 题目思路:一道AC自动机的模板题 备注:还不会字典树和KMP的尽早回去重修 如果让你在一篇 ...

  7. java运算符(超详细!!!)

    java运算符 一.算数运算符 符号 含义 + 加法 - 减法 * 乘法 / 除法 % 余数 ++ 自增 -- 自减 这些是常用的算数运算符,在java基础阶段,掌握这些就可 加减乘除运算符 代码实例 ...

  8. CSS进阶内容——布局技巧和细节修饰

    CSS进阶内容--布局技巧和细节修饰 我们在之前的文章中已经掌握了CSS的大部分内容,但仍有一些内容我们没有涉略,这篇文章就是为了补充前面没有涉及的内容,为我们的知识做出补充并且介绍一些布局技巧 当然 ...

  9. java的Test 如何使用@Autowired注解

    1.配置来至bean.xml @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = "class ...

  10. 闭包类型(Fn,FnMut,FnOnce)和move关键字

    move关键字是强制让环境变量的所有权转移到闭包中而不管是不是发生了所有权的转移 move关键字和匿名函数是否是FnOnce没有必然联系,之和匿名函数体有关 当匿名函数体里转移了环境变量的所有权的时候 ...