You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在单个Windows服务中托管多IHostBuilders:出现“未启动即停止”问题

解决Windows服务中托管两个Web应用时出现“Stopped without starting”异常的思路

问题根源

Windows服务的UseWindowsService()会将主机生命周期绑定到Windows服务的系统启停信号,但你用Task.WhenAny同时启动两个独立主机时,只有一个主机能正确关联到Windows服务的生命周期管理,另一个主机无法获取有效的生命周期信号,导致被直接终止,抛出“Stopped without starting”异常。而控制台模式下UseConsoleLifetime()基于控制台输入信号,允许多个独立主机同时运行,因此没有问题。

具体解决思路

方案1:合并到同一个Host(推荐)

ASP.NET Core支持在单个Host中托管多个Web应用,通过路径分支或不同端点区分,这是最简洁的方式,也符合Host设计的最佳实践。

示例代码:

var builder = WebApplication.CreateBuilder(args);
// 绑定Windows服务生命周期
builder.Host.UseWindowsService();

// 为两个应用注册各自的服务
// 应用1的服务配置
builder.Services.AddControllers();
// 应用2的服务配置
builder.Services.AddRazorPages();

var app = builder.Build();

// 应用1的中间件管道:匹配路径/app1的请求
app.MapWhen(context => context.Request.Path.StartsWithSegments("/app1"), app1 =>
{
    app1.UseRouting();
    app1.UseAuthorization();
    app1.MapControllers();
});

// 应用2的中间件管道:匹配路径/app2的请求
app.MapWhen(context => context.Request.Path.StartsWithSegments("/app2"), app2 =>
{
    app2.UseRouting();
    app2.UseAuthorization();
    app2.MapRazorPages();
});

// 也可以用不同端口区分:
// builder.WebHost.UseUrls("http://localhost:5000", "http://localhost:5001");
// 然后分别映射对应端口的路由逻辑

await app.RunAsync();

方案2:手动管理两个Host的生命周期

如果必须保持两个独立Host,需要让其中一个绑定Windows服务生命周期,另一个通过监听第一个Host的停止信号来同步启停。

示例代码:

// 第一个Host绑定Windows服务生命周期,作为主服务
var host1Builder = Host.CreateDefaultBuilder(args)
    .UseWindowsService()
    .ConfigureWebHostDefaults(webBuilder =>
    {
        webBuilder.UseStartup<StartupApp1>();
        webBuilder.UseUrls("http://localhost:5000");
    });

// 第二个Host不绑定Windows服务生命周期
var host2Builder = Host.CreateDefaultBuilder(args)
    .ConfigureWebHostDefaults(webBuilder =>
    {
        webBuilder.UseStartup<StartupApp2>();
        webBuilder.UseUrls("http://localhost:5001");
    });

var host1 = host1Builder.Build();
var host2 = host2Builder.Build();

// 获取host1的停止信号,用来同步终止host2
var lifetime = host1.Services.GetRequiredService<IHostApplicationLifetime>();
_ = host2.RunAsync(lifetime.ApplicationStopping);

// 启动主host1,它会响应Windows服务的启停命令
await host1.RunAsync();

额外排查步骤

  • 确认两个应用使用不同的端口/URL,避免端口冲突导致其中一个启动失败(控制台正常的话概率低,但可以排除)。
  • 为两个Host添加详细日志(比如适配Windows服务的EventLog日志),查看抛出异常的Host的具体启动失败细节,可能存在其他配置问题。

内容的提问来源于stack exchange,提问作者Bradley Plett

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 13:13:27