VS 2022 已移除 Windows Service 模板,推荐使用 .NET 6+ Worker Service 模板 + Microsoft.Extensions.Hosting.WindowsServices 包,通过 AddWindowsService() 配置服务名并调用 host.Run() 实现注册与运行。

Windows Service 项目模板在哪?VS 2022 还有吗
Visual Studio 2022 默认已移除「Windows Service (.NET Framework)」项目模板,.NET Core / .NET 5+ 也不再原生支持传统 ServiceBase 托管方式。想用 C# 写 Windows 服务,现在主流路径是:.NET 6+ + WorkerService 模板 + Microsoft.Extensions.Hosting.WindowsServices 包。
新建项目时选「Worker Service」,不是「Console App」——虽然底层都是控制台宿主,但 WorkerService 自带 IHostedService 基础结构,更贴近服务生命周期管理。
- 若必须兼容旧版(如需安装到 Windows Server 2008 或依赖
ServiceController直接通信),只能用 .NET Framework 4.7.2+ +ServiceBase,且需手动创建项目、添加引用 - .NET 6+ 的
WorkerService在 Windows 上可注册为服务,但不支持交互式桌面会话(AllowServiceToInteractWithDesktop已废弃) - 安装工具统一用
sc.exe或 PowerShellNew-Service,不再依赖InstallUtil.exe(它在 .NET Core+ 中不可用)
如何让 WorkerService 正确注册为 Windows 服务
核心是两步:修改宿主配置 + 添加 Windows 服务支持包。缺一不可,否则 sc start 会报错 1053(服务未及时响应启动或控制请求)。
先安装 NuGet 包:
dotnet add package Microsoft.Extensions.Hosting.WindowsServices
然后在 Program.cs 中启用 Windows 服务支持:
var builder = Host.CreateApplicationBuilder(args); builder.Services.AddHostedService(); // 必须加这行,否则无法作为服务运行 builder.Services.AddWindowsService(options => { options.ServiceName = "MyAppWorkerService"; }); var host = builder.Build(); host.Run();
-
options.ServiceName必须设置,且不能含空格或特殊字符(建议纯字母数字) - 不要调用
host.Start()后再host.WaitForShutdown()——host.Run()已封装完整服务生命周期 - 发布时用
dotnet publish -c Release -r win-x64 --self-contained true,生成独立部署包,避免目标机缺少运行时
服务启动失败常见错误和排查点
最常遇到的是事件查看器里显示「服务没有及时响应启动或控制请求」(错误 1053),本质是宿主初始化卡住或未正确绑定 Windows 服务上下文。
- 检查是否漏掉
AddWindowsService()调用 —— 这是最常见疏漏,会导致Environment.UserInteractive仍为true,服务进程误判为控制台模式 - 确认程序入口点(
Main方法)是否直接调用host.Run();若用了await host.RunAsync()但没设async Main,会编译失败 - 日志输出默认不写入 Windows 事件日志,需显式添加
builder.Logging.AddEventLog()并配置SourceName - 服务账户权限不足(比如用 LocalSystem 以外的账户运行,又试图访问网络路径或注册表)—— 临时调试可先设为
LocalSystem,上线再降权
如何安装、启动、卸载服务(命令行实操)
全部使用管理员权限的 PowerShell 或 CMD,别用普通用户窗口。
安装(假设发布后路径为 C:\MyApp\MyApp.exe):
sc create MyAppService binPath= "C:\MyApp\MyApp.exe" start= auto obj= "LocalSystem"
注意:binPath= 后面有空格,start= 和 obj= 同理;路径含空格必须用英文双引号包裹整个路径值,而不是只包路径。
启动与验证:
sc start MyAppService sc query MyAppService
卸载前务必先停止:
sc stop MyAppService sc delete MyAppService
-
sc query看STATE是否为RUNNING,WIN32_EXIT_CODE是否为0x0 - 如果服务一闪而退,立刻查 Windows 事件查看器 → Windows 日志 → 应用程序,筛选来源为你的
SourceName或.NET Runtime - 开发阶段可先以控制台模式运行(不注册服务):直接双击 exe 或
dotnet MyApp.dll,方便调试日志和异常堆栈
.NET 6+ 的 Windows 服务模型绕过了 ServiceBase,但生命周期钩子(如启动/停止通知)得靠 IHostedService.StartAsync()/StopAsync() 实现;很多人卡在「服务装上了却没执行业务逻辑」,往往是因为忘了在 StartAsync 里真正启动后台任务(比如 Task.Run 或定时器),或者异常没捕获导致 StartAsync 提前退出。








