.NET 6 Windows服务停止时写入两条重复事件日志问题
问题背景
该问题不会引发任何运行故障,仅系统事件日志表现不符合预期,相关信息如下:
- 实现基础:基于.NET 6参照微软官方Windows服务开发指南编写,当前版本清空了
ExecuteAsync方法内所有业务代码,服务暂不执行任何实际业务逻辑。 - 异常现象:停止服务时,系统事件日志会写入2条时间完全一致、内容完全重复的服务停止事件,对应截图如下:

- 项目核心代码:
Program.cs
Worker.csnamespace WindowsServiceSandbox { public class Program { public static void Main(string[] args) { var host = Host.CreateDefaultBuilder(args) .UseWindowsService(options => {options.ServiceName = "Test Windows Service";}) .ConfigureServices(services => {services.AddHostedService<Worker>();}) .Build(); host.Run(); } } }namespace WindowsServiceSandbox { public class Worker : BackgroundService { private readonly ILogger<Worker> _logger; public Worker(ILogger<Worker> logger) { _logger = logger; } protected override Task ExecuteAsync(CancellationToken stoppingToken) { return Task.CompletedTask; } } }
原因分析
重复日志的根源是ExecuteAsync实现不符合BackgroundService的生命周期设计逻辑:
- 直接返回
Task.CompletedTask意味着ExecuteAsync在服务启动完成的瞬间就同步执行结束。而BackgroundService的默认逻辑是:只要ExecuteAsync执行完成,就会自动触发主机停止流程,此时UseWindowsService内置的日志模块会写入第一条服务停止事件。 - 这时候服务本身还处于运行状态,后续手动触发服务停止操作时,Windows服务控制管理器会走标准的服务停止流程,日志模块会再写入一条完全相同的停止事件,最终出现两条同时间、同内容的重复记录。
本质是服务启动瞬间就因ExecuteAsync直接退出,隐式走完了一轮停止流程打出第一条日志,和后续手动触发的显式停止流程打出的日志重合,不是日志组件或者系统服务的bug。
修复方案
哪怕暂时没有业务逻辑需要执行,也要让ExecuteAsync持续等待到收到服务停止信号后再退出,不能直接返回完成状态。将Worker.cs中的ExecuteAsync方法修改为如下写法即可:
protected override async Task ExecuteAsync(CancellationToken stoppingToken) { try { // 无限等待,直到服务收到停止信号触发令牌取消 await Task.Delay(Timeout.Infinite, stoppingToken); } catch (OperationCanceledException) { // 停止时抛出取消异常属于预期行为,无需额外处理 } }
修改后服务启动后会正常驻留,不会在启动阶段提前触发隐式停止流程,停止服务时只会生成1条停止事件日志,表现符合预期。
内容的提问来源于stack exchange,提问作者Jason Richmeier
相关产品推荐
相关产品推荐

