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

如何在同一应用中托管WebApplication与BackgroundService

问题描述

我用dotnet new worker创建了一个命令行应用,用来托管BackgroundService实现,代码如下:

var host = Host.CreateDefaultBuilder(args)
    .ConfigureServices(services => {
        services.AddHostedService<MyBackgroundService>();
        services.AddSingleton<IMyType>(myinstance);
        // 其他服务配置...
    }).Build();

await host.RunAsync();

现在我想让这个应用同时托管Web API,目前我是在MyBackgroundService类里实例化了独立的WebApplicationBuilder,用的是另一套独立的服务、单例等资源:

var builder = WebApplication.CreateBuilder();

// Web相关配置...

var webApi = builder.Build();

// Web API后续配置...

await webApi.StartAsync(cancellationToken);

我希望能让两者共享同一个DI容器,该怎么操作?Web API用的是WebApplicationBuilder,而BackgroundService用的是DefaultBuilder(也就是IHostBuilder),有没有优雅的实现方式?

补充:我找到了相关文档,里面提到通用主机的ConfigureWebHostDefaults方法,但示例不够完整。我可以在通用主机上配置AddControllers()和AddRouting()这类服务,但调用Build()之后就没法再配置UseHttpLogging()、UseSwagger()或者MapControllers()了。


解决方案

最优雅的方式是基于WebApplicationBuilder来统一构建整个应用,因为它本质上已经集成了通用主机的能力,既能托管后台服务,也能配置Web API,天然共享同一个DI容器。具体步骤如下:

  1. 替换原有的Host.CreateDefaultBuilder为WebApplication.CreateBuilder,它会自动创建包含Web功能的通用主机
  2. 在同一个构建器中同时配置后台服务和Web API的服务
  3. 构建完成后,正常配置Web中间件和路由

示例代码如下:

var builder = WebApplication.CreateBuilder(args);

// 1. 配置共享的DI服务(包括原Worker应用的服务)
builder.Services.AddHostedService<MyBackgroundService>();
builder.Services.AddSingleton<IMyType>(myinstance);
// 其他共享服务配置...

// 2. 配置Web API所需的服务
builder.Services.AddControllers();
builder.Services.AddHttpLogging();
builder.Services.AddSwaggerGen();
// 其他Web服务配置...

var app = builder.Build();

// 3. 配置Web中间件(现在可以正常使用UseHttpLogging、UseSwagger等)
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpLogging();
app.UseRouting();
app.UseAuthorization();

// 4. 映射API路由
app.MapControllers();

// 5. 启动应用(同时托管后台服务和Web API)
await app.RunAsync();

核心优势

  • WebApplicationBuilder底层基于通用主机实现,完全兼容HostedService托管需求
  • 所有服务注册在同一DI容器,后台服务与Web API可直接注入共享实例
  • 构建后的WebApplication支持完整的中间件管道配置,解决了Build()后无法配置中间件的问题

兼容方案:基于通用主机配置

如果不想切换到WebApplicationBuilder,可以通过ConfigureWebHostDefaults扩展方法在通用主机上整合Web功能,中间件配置需嵌套在ConfigureWebHostDefaults内部:

var host = Host.CreateDefaultBuilder(args)
    .ConfigureServices(services => {
        // 配置后台服务与共享DI
        services.AddHostedService<MyBackgroundService>();
        services.AddSingleton<IMyType>(myinstance);
        // 配置Web API服务
        services.AddControllers();
        services.AddHttpLogging();
        services.AddSwaggerGen();
    })
    .ConfigureWebHostDefaults(webBuilder => {
        webBuilder.Configure(app => {
            // 配置Web中间件
            if (app.Environment.IsDevelopment())
            {
                app.UseSwagger();
                app.UseSwaggerUI();
            }

            app.UseHttpLogging();
            app.UseRouting();
            app.UseAuthorization();
            app.MapControllers();
        });
    })
    .Build();

await host.RunAsync();

这种方式也能实现共享DI,但可读性不如第一种方案,建议优先选择WebApplicationBuilder的统一构建方式。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 17:15:43