You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在同一进程中部署多个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

火山引擎 最新活动