当前位置: 首页 > news >正文

IHostedLifecycleService是如何管理后台任务的

在本文中,我们将介绍 IHostedLifecycleService接口,并通过几个用例来了解它是如何扩展 IHostedService接口并实现对托管服务生命周期更精细控制的。

一、什么是 IHostedService 接口

IHostedService接口是 .NET 中的一个强大功能,我们可以通过它管理应用程序中的后台任务,
它包含两个方法 StartAsyncStopAsync,其中 StartAsync方法用于实现启动后台任务的逻辑,当服务器启动并且 IHostApplicationLifetime.ApplicationStarted被触发时会调用这个方法。 当应用程序停止时会调用 StopAsync方法,我们使用它来停止后台任务并处理未托管的资源。

二、IHostedLifecycleService 接口

IHostedLifecycleService接口继承自 IHostedService接口,它对托管服务的启动和停止进行了更精细控制,引入了在服务启动或停止前后执行的新方法:StartingAsyncStartedAsyncStoppingAsyncStoppedAsync。下面我们来简单了解一下这四个方法的触发时机,首先,StartingAsync方法会在 StartAsync方法之前触发,而StartedAsync方法是在 StartAsync方法之后触发。同样,在 StoppingAsync方法之前会触发 StoppedAsync方法,在 StopAsync方法之后会触发 StoppedAsync方法。

下面,我们通过一个简单的例子来看一下在实际开发中的应用。
首先,我们定义了两个类 HostedService1 HostedService2,在这两个类中都实现了 IHostedLifecycleService接口:

public class HostedService1 (ILogger<HostedService1> logger) : IHostedLifecycleService
{public Task StartAsync(CancellationToken cancellationToken){logger.LogInformation($"Service {nameof(HostedService1 )} start.");return Task.CompletedTask;}public Task StartedAsync(CancellationToken cancellationToken){logger.LogInformation($"Service {nameof(HostedService1 )} started.");return Task.CompletedTask;}public Task StartingAsync(CancellationToken cancellationToken){logger.LogInformation($"Service {nameof(HostedService1 )} starting.");return Task.CompletedTask;}public Task StopAsync(CancellationToken cancellationToken){logger.LogInformation($"Service {nameof(HostedService1 )} stop.");return Task.CompletedTask;}public Task StoppedAsync(CancellationToken cancellationToken){logger.LogInformation($"Service {nameof(HostedService1 )} stopped.");return Task.CompletedTask;}public Task StoppingAsync(CancellationToken cancellationToken){logger.LogInformation($"Service {nameof(HostedService1 )} stopping.");return Task.CompletedTask;}
}public class HostedService2(ILogger<HostedService2> logger) : IHostedLifecycleService
{public Task StartAsync(CancellationToken cancellationToken){logger.LogInformation($"Service {nameof(HostedService2)} start.");return Task.CompletedTask;}public Task StartedAsync(CancellationToken cancellationToken){logger.LogInformation($"Service {nameof(HostedService2)} started.");return Task.CompletedTask;}public Task StartingAsync(CancellationToken cancellationToken){logger.LogInformation($"Service {nameof(HostedService2)} starting.");return Task.CompletedTask;}public Task StopAsync(CancellationToken cancellationToken){logger.LogInformation($"Service {nameof(HostedService2)} stop.");return Task.CompletedTask;}public Task StoppedAsync(CancellationToken cancellationToken){logger.LogInformation($"Service {nameof(HostedService2)} stopped.");return Task.CompletedTask;}public Task StoppingAsync(CancellationToken cancellationToken){logger.LogInformation($"Service {nameof(HostedService2)} stopping.");return Task.CompletedTask;}
}

在上面代码中,我们在每个方法里都打印了服务名和方法名,接着我们将这两个类注册为托管服务并运行应用程序:

var builder = Host.CreateApplicationBuilder(args);
builder.Services.AddHostedService<HostedService1>();
builder.Services.AddHostedService<HostedService2>();
var app = builder.Build();
app.Run();

上面代码中,我们使用 AddHostedService<THostedService>方法在 DI 容器中注册托管服务。 运行程序,将看到如下输出:
在这里插入图片描述
在输出的信息中,我们可以看到方法的调用顺序与预期一致。

三、当前托管服务的启动和停止

在默认情况下,应用会按顺序执行托管服务的启动和停止, 也就是说HostedService2StartingAsync方法只在HostedService1的相同方法返回之后执行。但是,从 .NET 8 开始我们可以通过设置ServiceStartConcurrentlyServiceStopConcurrently来改变这种行为,代码如下:

builder.Services.Configure<HostOptions>(options =>
{options.ServicesStartConcurrently = true;options.ServicesStopConcurrently = true;
});

设置为 true 时,所有托管服务将同时启动和停止,但是在所有服务的当前生命周期返回之前,任何服务的生命周期都不会启动。 简单说就是所有的 StartingAsync方法将首先并行执行,然后StartAsync方法也将并行执行,依此类推。

Tip:当我们的应用程序拥有多个托管服务时,并发启动可缩短启动和关闭的时间。

四、总结

通过 IHostedLifecycleService接口,我们可以更精细地控制每个服务在生命周期阶段启动和停止时发生的情况,可以初始化其他服务所需的依赖关系。 如果我们的应用程序实现了多个托管服务,就需要引入HostOptions来同时启动和停止服务。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 学生请假管理系统
  • 执行机构是怎么运作的
  • 超详细!!!electron-vite-vue开发桌面应用之应用更新版本提示(十三)
  • 软件测试学习笔记丨Docker 安装、管理、搭建服务
  • ASP.net core 8.0网站发布
  • Linux软件包循环依赖解决 彻底删除i386架构 更新软件源
  • uniapp uni-table合并单元格
  • unity3d入门教程四
  • Nginx怎么重新编译添加模块
  • 深入理解 Milvus:新一代向量数据库的基础技术与实战指南
  • 北斗卫星系统信号介绍
  • NVM (Node Version Manager) 使用教程
  • AB 1756-L62 与 AB 5069 通过串口通信
  • 从C语言过渡到C++
  • Kubernetes精讲之网络通信与调度
  • [js高手之路]搞清楚面向对象,必须要理解对象在创建过程中的内存表示
  • “Material Design”设计规范在 ComponentOne For WinForm 的全新尝试!
  • 【剑指offer】让抽象问题具体化
  • Angular2开发踩坑系列-生产环境编译
  • GDB 调试 Mysql 实战(三)优先队列排序算法中的行记录长度统计是怎么来的(上)...
  • iOS筛选菜单、分段选择器、导航栏、悬浮窗、转场动画、启动视频等源码
  • log4j2输出到kafka
  • mysql常用命令汇总
  • Python socket服务器端、客户端传送信息
  • python_bomb----数据类型总结
  • Theano - 导数
  • 阿里云购买磁盘后挂载
  • 代理模式
  • 服务器之间,相同帐号,实现免密钥登录
  • 回顾2016
  • 记一次和乔布斯合作最难忘的经历
  • 验证码识别技术——15分钟带你突破各种复杂不定长验证码
  • 在GitHub多个账号上使用不同的SSH的配置方法
  • ​探讨元宇宙和VR虚拟现实之间的区别​
  • # Python csv、xlsx、json、二进制(MP3) 文件读写基本使用
  • # 数据结构
  • #我与Java虚拟机的故事#连载15:完整阅读的第一本技术书籍
  • (3)医疗图像处理:MRI磁共振成像-快速采集--(杨正汉)
  • (C语言)strcpy与strcpy详解,与模拟实现
  • (delphi11最新学习资料) Object Pascal 学习笔记---第8章第5节(封闭类和Final方法)
  • (Ruby)Ubuntu12.04安装Rails环境
  • (补充)IDEA项目结构
  • (第9篇)大数据的的超级应用——数据挖掘-推荐系统
  • (二)c52学习之旅-简单了解单片机
  • (附源码)springboot建达集团公司平台 毕业设计 141538
  • (解决办法)ASP.NET导出Excel,打开时提示“您尝试打开文件'XXX.xls'的格式与文件扩展名指定文件不一致
  • (九)信息融合方式简介
  • .NET Compact Framework 多线程环境下的UI异步刷新
  • .NET Standard 支持的 .NET Framework 和 .NET Core
  • .NET/C# 推荐一个我设计的缓存类型(适合缓存反射等耗性能的操作,附用法)
  • .Net6使用WebSocket与前端进行通信
  • .net安装_还在用第三方安装.NET?Win10自带.NET3.5安装
  • .NET的数据绑定
  • .NET建议使用的大小写命名原则
  • .net解析传过来的xml_DOM4J解析XML文件