错误1053本质是SCM未收到就绪信号,需检查三要素:是否安装Microsoft.Extensions.Hosting.WindowsServices包、UseWindowsService()是否在Build()前调用且设置合法ServiceName、sc create的binPath路径格式是否正确。

Worker Service 在 .NET 6+ 中不是“能跑就行”的后台程序,直接双击运行或 sc create 后卡在 START_PENDING(错误 1053),几乎全是宿主配置、发布方式或服务上下文绑定的问题。
sc create 后服务卡在 START_PENDING 怎么快速定位
错误 1053 的本质是 SCM 没收到服务就绪信号,不是代码逻辑错,而是生命周期没接上。别急着改 Worker.ExecuteAsync,先查三件事:
-
Microsoft.Extensions.Hosting.WindowsServices包是否已安装:没它,UseWindowsService()是空操作 -
Program.cs中UseWindowsService()是否在Build()前调用:写在Run()后面、或ConfigureServices之前都无效 -
sc create的binPath=值是否含多余空格或引号不匹配:比如binPath="C:\MySvc\MySvc.exe"✅,binPath= "C:\MySvc\MySvc.exe"❌(等号后多空格)
查完立刻看 Windows 事件查看器 → 应用程序日志,筛选来源为 .NET Runtime 或你的服务名——90% 的真实报错(如找不到 System.ServiceProcess.ServiceController)都在那儿,不是控制台输出。
Program.cs 里 UseWindowsService() 调用位置和参数陷阱
UseWindowsService() 必须满足两个硬约束,否则注册成功也启动失败:
- 必须在
ConfigureServices()之后、Build()之前:顺序错会导致IHostApplicationLifetime等关键服务未注入,StopAsync不触发 -
options.ServiceName必须显式设置且不含空格/中文/特殊字符:比如builder.UseWindowsService(options => options.ServiceName = "MyAppSvc")✅,"My App Service"❌(注册时静默失败,sc query查不到)
别信“加了包就自动生效”——.NET SDK 不会自动补全 Windows 服务上下文,漏掉 UseWindowsService() 或放错位置,服务进程启动后立刻退出,连日志都来不及写。
dotnet publish 自包含发布为什么不能省
非自包含发布(即默认的 framework-dependent)在目标机缺少对应 .NET 运行时版本时,服务根本不会加载 DLL,事件日志只报模糊的 0xc0000135 或空白错误。正确命令是:
dotnet publish -c Release -r win-x64 --self-contained true
注意三点:
-
-r win-x64必须指定运行时标识符(RID),不带-r生成的 exe 无法被 SCM 加载 -
--self-contained true是强制项,不是可选项;哪怕目标机装了 .NET 8 运行时,SCM 仍可能因权限或路径问题拒绝加载共享框架 - 发布后检查输出目录:必须有
MySvc.exe+ 大量.dll文件(约 80MB+),如果只有几 MB,说明没走自包含流程
Worker.cs 中 ExecuteAsync 阻塞导致服务假死的典型表现
很多人把耗时操作塞进 ExecuteAsync 却没处理取消令牌,结果服务看似运行,实则逻辑卡死:
- 用
Thread.Sleep(5000)替代await Task.Delay(5000, stoppingToken):线程阻塞,stoppingToken无法传播,StopAsync永远不执行 - 同步 I/O 操作如
File.ReadAllText("config.json")无异常捕获:文件被占用或路径错时直接崩溃,但 SCM 不报错,只显示“服务意外终止” - 未
await的异步调用如httpClient.GetAsync(url)没加.ConfigureAwait(false):在 Windows 服务上下文中可能引发死锁
真正安全的循环结构只有一种模式:
protected override async Task ExecuteAsync(CancellationToken stoppingToken)<br>{<br> while (!stoppingToken.IsCancellationRequested)<br> {<br> try<br> {<br> await DoWorkAsync(stoppingToken);<br> }<br> catch (OperationCanceledException)<br> {<br> break;<br> }<br> catch (Exception ex)<br> {<br> _logger.LogError(ex, "Work failed");<br> }<br> await Task.Delay(5000, stoppingToken);<br> }<br>}
所有外部依赖(数据库、HTTP、文件)必须支持 CancellationToken,且不能假设“只要不抛异常就安全”——超时、连接池耗尽、磁盘满,都会让服务在无人察觉的情况下停止响应。


















