如何在ASP.NET Core中按层为接口注入不同实现?
在ASP.NET Core中为不同仓储注入不同IMySqlConnection的方案
针对你提到的场景——Customer和Employee仓储需要不同的IMySqlConnection实例,有几种实用的解决方案,下面按推荐程度排序:
1. 封装特定连接接口(最推荐)
直接为不同仓储定义专属的连接接口,继承自IMySqlConnection,这样依赖关系更清晰,也避免了区分命名的麻烦。
示例代码:
// 定义专属接口 public interface ICustomerDbConnection : IMySqlConnection { } public interface IEmployeeDbConnection : IMySqlConnection { } // 注册服务 builder.Services.AddScoped<ICustomerDbConnection>(sp => { var config = sp.GetRequiredService<IConfiguration>(); var connString = config.GetConnectionString("CustomerDB"); return new MySqlConnection(connString); }); builder.Services.AddScoped<IEmployeeDbConnection>(sp => { var config = sp.GetRequiredService<IConfiguration>(); var connString = config.GetConnectionString("EmployeeDB"); return new MySqlConnection(connString); }); // 仓储依赖专属接口 public class CustomerRepository { private readonly ICustomerDbConnection _conn; public CustomerRepository(ICustomerDbConnection conn) { _conn = conn; } } public class EmployeeRepository { private readonly IEmployeeDbConnection _conn; public EmployeeRepository(IEmployeeDbConnection conn) { _conn = conn; } }
这种方式的优势在于语义明确,依赖关系一目了然,后续维护时不容易出错,完全符合依赖倒置原则。
2. 使用.NET 6+的键控服务(Keyed Services)
ASP.NET Core从.NET 6开始支持键控服务,可以通过命名来区分同一接口的不同实现,然后在构造函数中指定要注入的实例。
示例代码:
// 注册键控服务 builder.Services.AddKeyedScoped<IMySqlConnection>("CustomerConn", sp => { var connString = sp.GetRequiredService<IConfiguration>().GetConnectionString("CustomerDB"); return new MySqlConnection(connString); }); builder.Services.AddKeyedScoped<IMySqlConnection>("EmployeeConn", sp => { var connString = sp.GetRequiredService<IConfiguration>().GetConnectionString("EmployeeDB"); return new MySqlConnection(connString); }); // 仓储中通过[FromKeyedServices]标记注入指定实例 public class CustomerRepository { private readonly IMySqlConnection _conn; public CustomerRepository([FromKeyedServices("CustomerConn")] IMySqlConnection conn) { _conn = conn; } } public class EmployeeRepository { private readonly IMySqlConnection _conn; public EmployeeRepository([FromKeyedServices("EmployeeConn")] IMySqlConnection conn) { _conn = conn; } }
这种方式不需要新增接口,适合不想修改现有接口定义的场景,但需要注意字符串键的一致性,避免拼写错误。
3. 工厂模式(动态创建)
如果需要更灵活的控制(比如根据运行时参数选择连接),可以使用工厂模式,让仓储从工厂获取对应的连接实例。
示例代码:
// 定义工厂接口 public interface IDbConnectionFactory { IMySqlConnection GetCustomerConnection(); IMySqlConnection GetEmployeeConnection(); } // 实现工厂 public class DbConnectionFactory : IDbConnectionFactory { private readonly IConfiguration _config; public DbConnectionFactory(IConfiguration config) { _config = config; } public IMySqlConnection GetCustomerConnection() { return new MySqlConnection(_config.GetConnectionString("CustomerDB")); } public IMySqlConnection GetEmployeeConnection() { return new MySqlConnection(_config.GetConnectionString("EmployeeDB")); } } // 注册工厂 builder.Services.AddScoped<IDbConnectionFactory, DbConnectionFactory>(); // 仓储注入工厂并获取连接 public class CustomerRepository { private readonly IMySqlConnection _conn; public CustomerRepository(IDbConnectionFactory factory) { _conn = factory.GetCustomerConnection(); } }
这种方式适合需要动态切换连接的场景,但仓储需要主动调用工厂方法,耦合度略高于前两种方案。
内容的提问来源于stack exchange,提问作者Kyle C
相关产品推荐
相关产品推荐

