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

ASP.NET Core中如何在新建宿主内复用现有DI容器

实现子宿主复用主宿主DI容器的方案

核心原理

ASP.NET Core的依赖注入体系原生支持父子容器层级结构,无需重复注册主宿主的所有服务,只需将主宿主已构建完成的根IServiceProvider作为子宿主容器的父级即可,完全避免重复注册带来的性能和内存损耗。

实现步骤

1. 调整后台服务字段存储主宿主根服务提供者

你不需要存储IServiceCollection,你的BackgroundWebHost作为主宿主托管的后台服务,可以直接在构造函数注入主宿主的根IServiceProvider,这是已经完成所有服务注册的最终容器实例:

public class BackgroundWebHost : BackgroundService
{
    // 存储主宿主的根服务提供者
    private readonly IServiceProvider _rootServiceProvider;

    public BackgroundWebHost(IServiceProvider rootServiceProvider)
    {
        _rootServiceProvider = rootServiceProvider;
    }

2. 自定义服务提供工厂绑定父子容器

创建自定义的IServiceProviderFactory实现,构建子宿主的容器时指定父级为_rootServiceProvider:

public class HierarchicalServiceProviderFactory : IServiceProviderFactory<IServiceCollection>
{
    private readonly IServiceProvider _parentProvider;
    private readonly ServiceProviderOptions _options;

    public HierarchicalServiceProviderFactory(IServiceProvider parentProvider, ServiceProviderOptions options = null)
    {
        _parentProvider = parentProvider ?? throw new ArgumentNullException(nameof(parentProvider));
        _options = options ?? new ServiceProviderOptions();
    }

    public IServiceCollection CreateBuilder(IServiceCollection services)
    {
        return services;
    }

    public IServiceProvider CreateServiceProvider(IServiceCollection containerBuilder)
    {
        // 构建子容器时绑定父容器
        return containerBuilder.BuildServiceProvider(_options, _parentProvider);
    }
}

3. 修改子宿主创建逻辑,使用自定义工厂

调整你的CreateHost方法,指定使用刚才实现的层级服务提供工厂:

private IHost CreateHost(string[] args)
{
    return Host.CreateDefaultBuilder(args)
        // 注册子宿主自身需要的独有服务(如果有)
        .ConfigureServices((ctx, services) =>
        {
            // 这里只需要注册子宿主特有的服务,不需要重复注册主宿主的服务
        })
        // 使用自定义的层级服务提供工厂,绑定主宿主根容器为父级
        .UseServiceProviderFactory(new HierarchicalServiceProviderFactory(_rootServiceProvider))
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.ConfigureKestrel(options =>
            {
                options.ListenAnyIP(4999, listenOptions =>
                {
                    listenOptions.Protocols = HttpProtocols.Http2;
                });
            });
            webBuilder.UseStartup<Startup>();
        })
        .Build();
}

注意事项

  • 生命周期继承:父容器的单例服务全局共享,子容器的单例仅在子宿主范围内生效,子宿主销毁时不会释放父容器的任何服务
  • 服务覆盖规则:如果子容器注册了和父容器同类型的服务,子宿主内解析时会优先使用子容器的注册
  • 避免内存泄漏:不要在子容器中长时持有父容器的范围服务,如需使用请通过IServiceScopeFactory创建独立范围解析
  • 如果你必须使用已拿到的IServiceCollection,请确保主宿主已经完成Build()操作生成IServiceProvider后再创建子宿主,否则主容器的服务注册不完整

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 23:24:03