ASP.NET中为键控依赖注入注册多个DbCheck实例的问题
解决方案
1. 注册为接口集合(推荐)
因为你的DbCheck实现了ICheck接口,可以将三个实例都注册为ICheck的作用域服务,这样注入IEnumerable<ICheck>就能获取所有实例,再根据自定义标识区分:
// 注意给每个实例设置不同的checkName用于后续筛选 var db1 = new DbCheck("db1", dataConnection1, tableInfo1); services.AddScoped<ICheck>(_ => db1); var db2 = new DbCheck("db2", dataConnection2, tableInfo2); services.AddScoped<ICheck>(_ => db2); var db3 = new DbCheck("db3", dataConnection3, tableInfo3); services.AddScoped<ICheck>(_ => db3);
使用时直接注入IEnumerable<ICheck>,遍历筛选需要的实例:
public class HealthChecker { private readonly IEnumerable<ICheck> _dbChecks; public HealthChecker(IEnumerable<ICheck> dbChecks) { _dbChecks = dbChecks; } public void RunChecks() { var db1Check = _dbChecks.First(c => c.CheckName == "db1"); db1Check.Execute(); // 其他实例同理 } }
2. 正确使用键控依赖注入(.NET 6+)
你之前写的AddKeyedScoped参数形式有误,正确用法是将键作为第二个参数,工厂方法作为第三个参数(直接传入实例时可忽略服务提供者参数):
var db1 = new DbCheck(checkName, dataConnection, tableInfo); services.AddKeyedScoped<DbCheck>("db1", _ => db1); var db2 = new DbCheck(checkName, dataConnection, tableInfo); services.AddKeyedScoped<DbCheck>("db2", _ => db2); var db3 = new DbCheck(checkName, dataConnection, tableInfo); services.AddKeyedScoped<DbCheck>("db3", _ => db3);
使用时通过[FromKeyedServices]特性注入,或手动从服务提供者获取:
// 构造函数注入方式 public class HealthChecker { public HealthChecker([FromKeyedServices("db1")] DbCheck db1Check, [FromKeyedServices("db2")] DbCheck db2Check) { // 使用实例 } } // 手动获取方式 var db1Check = services.GetRequiredKeyedService<DbCheck>("db1");
注意:键控服务仅支持.NET 6及以上版本,项目版本过低则无法使用。
3. 自定义工厂类管理实例
如果受限于NuGet包约束,可创建工厂类封装所有DbCheck实例,通过键直接获取:
public class DbCheckFactory { private readonly Dictionary<string, DbCheck> _checkInstances; public DbCheckFactory(DbCheck db1, DbCheck db2, DbCheck db3) { _checkInstances = new Dictionary<string, DbCheck> { {"db1", db1}, {"db2", db2}, {"db3", db3} }; } public DbCheck GetCheck(string key) { if (_checkInstances.TryGetValue(key, out var check)) { return check; } throw new KeyNotFoundException($"未找到键为 {key} 的DbCheck实例"); } }
注册时先分别注册三个DbCheck实例,再注册工厂:
var db1 = new DbCheck(checkName, dataConnection, tableInfo); services.AddScoped(_ => db1); var db2 = new DbCheck(checkName, dataConnection, tableInfo); services.AddScoped(_ => db2); var db3 = new DbCheck(checkName, dataConnection, tableInfo); services.AddScoped(_ => db3); services.AddScoped<DbCheckFactory>();
使用时注入工厂类,调用GetCheck方法获取实例:
public class HealthChecker { private readonly DbCheckFactory _checkFactory; public HealthChecker(DbCheckFactory checkFactory) { _checkFactory = checkFactory; } public void RunDb1Check() { var db1Check = _checkFactory.GetCheck("db1"); db1Check.Execute(); } }
关于NuGet包的疑问
继承DbCheck子类触发错误,大概率是NuGet包内部对DbCheck类型有约束(比如标记为sealed密封类,或内部逻辑仅识别原始DbCheck类型)。建议查看包的官方文档,或联系维护者确认是否支持多实例注册、是否有官方推荐的多数据库健康检查实现方式。
内容的提问来源于stack exchange,提问作者user19627737
相关产品推荐
相关产品推荐

