如何基于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及以上版本,框架内置的键服务是最简洁的实现方式:
- 注册时指定键
替换原注册代码,用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; });
- 构造函数中按键注入
修改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实例:
- 创建解析接口与实现类
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属性,用于实例筛选
- 注册解析类与所有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>();
- 在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
相关产品推荐
相关产品推荐

