如何在同一进程中部署多个ASP.NET Core 2.0 Windows服务
解决同一Windows服务进程中托管多个ASP.NET Core 2.0应用的问题
你遇到的问题其实很典型——默认情况下每个ASP.NET Core Windows服务都是独立进程,但要把多个应用塞进同一个进程,核心思路是用一个主服务程序来托管多个WebHost实例,每个WebHost对应一个你的应用。下面是具体的实现步骤和注意事项:
核心思路
创建一个控制台应用作为"主服务载体",在里面启动多个ASP.NET Core应用的WebHost,然后将这个控制台应用注册为Windows服务,这样所有应用就会在同一个进程里运行了。
具体实现步骤
1. 准备项目结构
- 新建一个控制台应用(.NET Core 2.0),作为主服务项目(比如命名为
MultiAppWindowsService)。 - 将你要托管的每个ASP.NET Core 2.0应用项目,以类库引用的方式添加到主服务项目中(确保每个应用的
Startup类能被主程序访问)。 - 给主服务项目安装必要的NuGet包:
Microsoft.AspNetCore.Hosting.WindowsServices(用于支持Windows服务托管)和Microsoft.AspNetCore(因为要创建WebHost)。
2. 编写主服务代码
步骤2.1:创建Windows服务类
这个类负责管理多个WebHost的启动和停止:
using System.ServiceProcess; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Hosting; namespace MultiAppWindowsService { public class MultiAppHostService : ServiceBase { private CancellationTokenSource _cts; private Task[] _hostTasks; protected override void OnStart(string[] args) { _cts = new CancellationTokenSource(); // 启动第一个应用的WebHost var host1 = new WebHostBuilder() .UseKestrel(options => options.ListenAnyIP(5000)) // 第一个应用的端口 .UseStartup<YourFirstApp.Startup>() // 替换为第一个应用的Startup类 .Build(); // 启动第二个应用的WebHost var host2 = new WebHostBuilder() .UseKestrel(options => options.ListenAnyIP(5001)) // 第二个应用的端口,必须和第一个不同 .UseStartup<YourSecondApp.Startup>() // 替换为第二个应用的Startup类 .Build(); // 异步运行两个WebHost,避免阻塞OnStart方法 _hostTasks = new[] { host1.RunAsync(_cts.Token), host2.RunAsync(_cts.Token) }; } protected override void OnStop() { // 发送取消信号,停止所有WebHost _cts.Cancel(); Task.WhenAll(_hostTasks).Wait(); _cts.Dispose(); } } }
步骤2.2:编写Program入口
处理交互式调试和服务运行两种模式:
using System; using System.Threading.Tasks; using Microsoft.AspNetCore.Hosting; namespace MultiAppWindowsService { public class Program { public static void Main(string[] args) { if (Environment.UserInteractive) { // 交互式模式:直接运行,方便本地调试 var cts = new CancellationTokenSource(); var host1 = new WebHostBuilder() .UseKestrel(options => options.ListenAnyIP(5000)) .UseStartup<YourFirstApp.Startup>() .Build(); var host2 = new WebHostBuilder() .UseKestrel(options => options.ListenAnyIP(5001)) .UseStartup<YourSecondApp.Startup>() .Build(); var tasks = new[] { host1.RunAsync(cts.Token), host2.RunAsync(cts.Token) }; Console.WriteLine("Press any key to stop..."); Console.ReadKey(); cts.Cancel(); Task.WhenAll(tasks).Wait(); } else { // 服务模式:作为Windows服务运行 ServiceBase.Run(new MultiAppHostService()); } } } }
3. 发布并安装服务
- 将主服务项目发布为自包含应用(避免目标服务器缺少.NET Core运行时):
dotnet publish -c Release -r win-x64 --self-contained true - 用Windows的
sc命令安装服务(以管理员身份运行命令提示符):sc create MultiAppService binPath= "C:\Path\To\Your\Published\MultiAppWindowsService.exe" DisplayName= "Multi-App ASP.NET Core Service" - 启动服务:
sc start MultiAppService
关键注意事项
- 端口冲突:每个应用必须配置不同的Kestrel监听端口,否则会启动失败。
- 权限问题:Windows服务默认使用
LocalSystem账号运行,确保该账号有访问应用所需资源(数据库、文件等)的权限;如果需要,可以修改服务的运行账号。 - 日志配置:给每个应用配置独立的日志(比如用Serilog、NLog),方便排查问题,避免日志混在一起难以区分。
- 优雅停止:一定要在
OnStop方法中正确取消所有WebHost的异步任务,避免进程残留或资源泄漏。
内容的提问来源于stack exchange,提问作者ken




