.NET 5 Worker服务如何检测系统关机事件
.NET 5 Worker 服务实现系统关机前自定义逻辑的方案
.NET 5及后续版本的Worker服务,默认通过Microsoft.Extensions.Hosting.WindowsServices包提供Windows服务承载能力,没有直接暴露和.NET Framework Windows服务完全同名的OnShutdown()重写入口,可通过以下两种方案实现完全同等的关机前自定义逻辑执行能力:
方案1:监听主机生命周期停止令牌(推荐)
- 前置依赖:确保项目已安装
Microsoft.Extensions.Hosting.WindowsServicesNuGet包,且主机构建阶段已调用UseWindowsService()开启Windows服务承载支持。 - 触发逻辑:Windows向服务发送关机通知时,主机注入的停止令牌会自动标记为取消状态,此时执行的代码块和传统.NET Framework服务
OnShutdown()的触发时机完全一致。 - 配置优化:可通过Windows服务配置项自定义关机等待超时,避免自定义逻辑未执行完就被系统强制终止。
Program.cs 基础配置示例:
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; var host = Host.CreateDefaultBuilder(args) .UseWindowsService(options => { options.CanShutdown = true; // 显式开启系统关机事件接收,默认值即为true options.ShutdownTimeout = TimeSpan.FromSeconds(30); // 给自定义清理逻辑预留30秒执行时间,可按需调整 }) .ConfigureServices(services => { services.AddHostedService<Worker>(); }) .Build(); await host.RunAsync();
Worker服务中实现关机逻辑示例:
public class Worker : BackgroundService { private readonly ILogger<Worker> _logger; public Worker(ILogger<Worker> logger) { _logger = logger; } protected override async Task ExecuteAsync(CancellationToken stoppingToken) { // 服务正常运行时的常驻业务逻辑 while (!stoppingToken.IsCancellationRequested) { _logger.LogInformation("Worker运行中: {time}", DateTimeOffset.Now); await Task.Delay(1000, stoppingToken); } // 代码执行到此处即代表收到系统关机/服务停止信号,对应传统OnShutdown触发时机 _logger.LogInformation("收到关机信号,开始执行自定义清理逻辑"); // 此处放置原OnShutdown()方法内的所有自定义逻辑 await ExecuteCustomShutdownLogic(); } private async Task ExecuteCustomShutdownLogic() { // 实现资源释放、数据持久化、状态上报等自定义需求 await Task.CompletedTask; } }
注意:不要把关机清理逻辑写在类的Dispose重写方法中,该阶段主机已开始回收核心服务依赖,极易出现依赖对象已释放导致的空引用、调用失败问题。
方案2:自定义服务生命周期类重写OnShutdown(对齐.NET Framework开发习惯)
如果需要完全复刻传统.NET Framework服务重写OnShutdown()的开发体验,可以自定义继承WindowsServiceLifetime类,直接重写对应方法,替换默认的服务生命周期实现即可。
自定义生命周期类示例:
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting.WindowsServices; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; public class CustomWindowsServiceLifetime : WindowsServiceLifetime { private readonly ILogger<CustomWindowsServiceLifetime> _logger; public CustomWindowsServiceLifetime( IHostApplicationLifetime applicationLifetime, ILogger<CustomWindowsServiceLifetime> logger, IOptions<HostOptions> hostOptions) : base(applicationLifetime, logger, hostOptions) { _logger = logger; } protected override void OnShutdown() { _logger.LogInformation("触发系统关机事件,执行OnShutdown自定义逻辑"); // 此处直接放置原.NET Framework服务中OnShutdown()内的业务逻辑 RunCustomShutdownTasks(); base.OnShutdown(); } private void RunCustomShutdownTasks() { // 自定义关机逻辑实现 } }
在服务配置阶段替换默认生命周期实现:
.ConfigureServices(services => { services.AddSingleton<IHostLifetime, CustomWindowsServiceLifetime>(); services.AddHostedService<Worker>(); })
注意:Windows系统默认给服务预留的关机执行时间存在全局上限,不要在关机逻辑中写入长时间阻塞的操作。如果确实需要更长的执行窗口,需要同步修改系统对应注册表的服务关机等待时长配置,否则逻辑会被系统强制中断。
内容的提问来源于stack exchange,提问作者Huzaifa Baloch
相关产品推荐
相关产品推荐

