Dotnet 5.0服务EXE运行正常,注册为Windows服务启动报1053超时错误
错误重写
StartAsync方法导致启动流程阻塞
你重写了BackgroundService的StartAsync方法后直接await ExecuteAsync(cancellationToken),而ExecuteAsync内是无限循环的常驻逻辑,会导致StartAsync永远无法返回。Windows服务控制器要求服务启动时必须在规定时间内返回成功信号,你这里StartAsync一直阻塞不返回,就会触发1053超时错误。
默认的BackgroundService.StartAsync实现会将ExecuteAsync放到后台任务运行,同时立刻返回启动成功信号,不需要自行调用ExecuteAsync。未添加Windows服务兼容配置
Dotnet的通用宿主默认没有适配Windows服务的通信逻辑,你需要在Program.cs的IHostBuilder配置链中添加UseWindowsService()扩展,才能让宿主正确和Windows服务控制器交互,上报启动、停止状态。
步骤1:修改Program.cs添加Windows服务适配
首先安装Microsoft.Extensions.Hosting.WindowsServices NuGet包,然后修改CreateHostBuilder逻辑:
public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .UseWindowsService() // 新增这行,适配Windows服务通信逻辑 .ConfigureAppConfiguration((hostingContext, config) => { //config.AddJsonFile("custom_settings.json"); }) .ConfigureLogging(logging => { //builder.AddFile("logs/app-{Date}.json"), isJson: true); }) .ConfigureServices((hostContext, services) => { services.AddHostedService<Worker>(); });
步骤2:修正Worker.cs的StartAsync重写逻辑
保留启动/停止日志逻辑的前提下,不要自行调用ExecuteAsync,改为调用基类的StartAsync实现:
public override async Task StartAsync(CancellationToken cancellationToken) { string path = @"C:\log.txt"; string startText = "Start" + Environment.NewLine; File.AppendAllText(path, startText); // 调用基类默认实现,自动调度ExecuteAsync到后台运行 await base.StartAsync(cancellationToken); } public override async Task StopAsync(CancellationToken cancellationToken) { string path = @"C:\log.txt"; string stopText = "Stop" + Environment.NewLine; File.AppendAllText(path, stopText); await base.StopAsync(cancellationToken); }
步骤3:优化FileSystemWatcher生命周期(可选但建议)
把FileSystemWatcher定义为Worker类的私有成员变量,不要放在ExecuteAsync里作为局部变量,避免被GC意外回收导致事件不触发。
步骤4:重新打包发布
重新执行dotnet publish -c Release -r win10-x64,替换目标机器上的文件,重新注册服务即可正常启动。
- 不需要替换
BackgroundService为传统WindowsService实现,BackgroundService配合UseWindowsService()完全可以满足需求 - 不需要用
InstallUtil注册,sc.exe注册完全符合要求 - 不需要额外实现信号逻辑,添加
UseWindowsService()后宿主会自动处理和服务控制器的通信
内容的提问来源于stack exchange,提问作者Jimmy Long

