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

如何基于ClusterName从依赖注入中获取指定的IDbFactory实例?

问题描述

在依赖注入(DI)容器中注册了两个对应不同DatabaseClient的IDbFactory单例服务,代码如下:

_ = services.AddSingleton<IDbFactory>(x =>
{
    var dbFactory = new DbFactory(x.GetRequiredService<IConfiguration>(), x.GetRequiredService<IKeyVaultManager>(), "ClusterName1");
    return dbFactory;
});

_ = services.AddSingleton<IDbFactory>(x =>
{
    var dbFactory = new DbFactory(x.GetRequiredService<IConfiguration>(), x.GetRequiredService<IKeyVaultManager>(), "ClusterName2");
    return dbFactory;
});

现在希望在TestRepository的构造函数中,以ClusterName作为键获取对应的IDbFactory实例,请问该如何实现?

public class TestRepository : DbRepository<SomeEntity>, ITestRepository
{
    public TestRepository(ILogger<DbRepository<SomeEntity>> logger, IDbFactory clientFactory)
        : base(logger, clientFactory)
    {
    }
}
解决方案

方法1:使用.NET 6+的键服务(Keyed Services)

如果项目基于.NET 6及以上版本,框架内置的键服务是最简洁的实现方式:

  1. 注册时指定键
    替换原注册代码,用AddKeyedSingleton将ClusterName作为标识键:
_ = services.AddKeyedSingleton<IDbFactory>("ClusterName1", x =>
{
    var dbFactory = new DbFactory(x.GetRequiredService<IConfiguration>(), x.GetRequiredService<IKeyVaultManager>(), "ClusterName1");
    return dbFactory;
});

_ = services.AddKeyedSingleton<IDbFactory>("ClusterName2", x =>
{
    var dbFactory = new DbFactory(x.GetRequiredService<IConfiguration>(), x.GetRequiredService<IKeyVaultManager>(), "ClusterName2");
    return dbFactory;
});
  1. 构造函数中按键注入
    修改TestRepository的构造函数,通过[FromKeyedServices]特性指定要获取的实例键:
public class TestRepository : DbRepository<SomeEntity>, ITestRepository
{
    public TestRepository(ILogger<DbRepository<SomeEntity>> logger, 
                          [FromKeyedServices("ClusterName1")] IDbFactory clientFactory)
        : base(logger, clientFactory)
    {
    }
}

如果需要动态指定键(比如从配置读取),可以注入IServiceProvider,调用GetRequiredKeyedService<IDbFactory>("目标ClusterName")获取对应实例。

方法2:自定义工厂类管理实例

若项目版本不支持键服务,可自行封装解析类来管理不同IDbFactory实例:

  1. 创建解析接口与实现类
public interface IDbFactoryResolver
{
    IDbFactory GetDbFactory(string clusterName);
}

public class DbFactoryResolver : IDbFactoryResolver
{
    private readonly IEnumerable<IDbFactory> _dbFactories;

    public DbFactoryResolver(IEnumerable<IDbFactory> dbFactories)
    {
        _dbFactories = dbFactories;
    }

    public IDbFactory GetDbFactory(string clusterName)
    {
        var factory = _dbFactories.FirstOrDefault(f => f.ClusterName == clusterName);
        if (factory == null)
        {
            throw new ArgumentException($"未找到对应集群 {clusterName} 的IDbFactory实例");
        }
        return factory;
    }
}

注意:需要确保DbFactory类暴露ClusterName属性,用于实例筛选

  1. 注册解析类与所有IDbFactory
// 先注册两个IDbFactory实例
_ = services.AddSingleton<IDbFactory>(x =>
{
    var dbFactory = new DbFactory(x.GetRequiredService<IConfiguration>(), x.GetRequiredService<IKeyVaultManager>(), "ClusterName1");
    return dbFactory;
});

_ = services.AddSingleton<IDbFactory>(x =>
{
    var dbFactory = new DbFactory(x.GetRequiredService<IConfiguration>(), x.GetRequiredService<IKeyVaultManager>(), "ClusterName2");
    return dbFactory;
});

// 注册解析类
_ = services.AddSingleton<IDbFactoryResolver, DbFactoryResolver>();
  1. 在Repository中使用解析类
public class TestRepository : DbRepository<SomeEntity>, ITestRepository
{
    public TestRepository(ILogger<DbRepository<SomeEntity>> logger, 
                          IDbFactoryResolver factoryResolver)
        : base(logger, factoryResolver.GetDbFactory("ClusterName1"))
    {
    }
}

方法3:直接注入集合后筛选

简单场景下,可直接注入所有IDbFactory实例,在构造函数中筛选目标实例:

public class TestRepository : DbRepository<SomeEntity>, ITestRepository
{
    public TestRepository(ILogger<DbRepository<SomeEntity>> logger, 
                          IEnumerable<IDbFactory> dbFactories)
        : base(logger, dbFactories.First(f => f.ClusterName == "ClusterName1"))
    {
    }
}

这种方式适合单次使用,但若多个地方需要筛选,会产生重复代码,不如自定义解析类优雅。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 06:45:16