.NET Core 2.0中ADO.NET的依赖注入:连接字符串注入问题求助
嘿,我之前也碰到过类似的情况——放弃EF改用ADO.NET后,确实得调整依赖注入的方式来传递连接字符串,刚好适配你的分层架构,给你几个实用的方案:
方案一:直接注入连接字符串(最简单直接)
先在根MVC项目的Startup.cs里,从配置文件读取连接字符串,再注册到DI容器里:
public void ConfigureServices(IServiceCollection services) { // 从appsettings.json里读你的数据库连接字符串 var dbConnectionString = Configuration.GetConnectionString("YourDatabase"); // 字符串是不可变的,注册成单例完全没问题 services.AddSingleton(dbConnectionString); // 注册你的仓储类,比如IProductRepository和对应的实现 services.AddScoped<IProductRepository, ProductRepository>(); // 其他MVC相关配置... }
然后在核心项目的仓储类里,直接通过构造函数注入这个字符串就行:
public class ProductRepository : IProductRepository { private readonly string _connectionString; // 构造函数注入连接字符串 public ProductRepository(string connectionString) { _connectionString = connectionString ?? throw new ArgumentNullException(nameof(connectionString)); } // 用ADO.NET操作数据库的时候直接用这个字符串 public async Task<Product> GetProductById(int id) { using (var conn = new SqlConnection(_connectionString)) { await conn.OpenAsync(); // 这里写你的SQL命令逻辑... } } }
这个方案的好处就是简单直接,不需要额外封装,适合小到中型项目。
方案二:封装成配置类(更规范,方便扩展)
如果之后你可能需要加更多数据库相关配置(比如命令超时时间),可以把这些配置封装成一个类,更符合.NET Core的配置规范:
首先在核心项目里定义配置类:
public class DatabaseConfig { public string ConnectionString { get; set; } // 可以加其他配置项,比如默认命令超时 public int DefaultCommandTimeout { get; set; } = 30; }
然后在根MVC项目的Startup.cs里绑定配置并注册:
public void ConfigureServices(IServiceCollection services) { // 把appsettings.json里的Database节点绑定到DatabaseConfig services.Configure<DatabaseConfig>(Configuration.GetSection("Database")); // 注册仓储 services.AddScoped<IProductRepository, ProductRepository>(); // 其他配置... }
对应的appsettings.json配置大概是这样:
{ "Database": { "ConnectionString": "Server=.;Database=YourDb;Trusted_Connection=True;", "DefaultCommandTimeout": 60 } }
最后在仓储类里注入IOptions<DatabaseConfig>:
public class ProductRepository : IProductRepository { private readonly DatabaseConfig _dbConfig; public ProductRepository(IOptions<DatabaseConfig> dbConfig) { _dbConfig = dbConfig.Value ?? throw new ArgumentNullException(nameof(dbConfig)); if (string.IsNullOrEmpty(_dbConfig.ConnectionString)) { throw new ArgumentException("数据库连接字符串不能为空", nameof(dbConfig)); } } // 使用的时候就可以拿到所有配置项 public async Task<IEnumerable<Product>> GetAllProducts() { using (var conn = new SqlConnection(_dbConfig.ConnectionString)) { conn.CommandTimeout = _dbConfig.DefaultCommandTimeout; await conn.OpenAsync(); // 执行查询逻辑... } } }
这个方案扩展性更强,后续加配置项很方便,适合需要多配置的场景。
方案三:注入数据库连接工厂(灵活度更高)
如果你的项目需要更灵活的连接管理——比如不同仓储用不同连接,或者需要统一处理连接的创建逻辑,那可以封装一个连接工厂:
先在核心项目定义接口和实现:
public interface IDbConnectionFactory { IDbConnection CreateConnection(); } public class SqlServerConnectionFactory : IDbConnectionFactory { private readonly string _connectionString; public SqlServerConnectionFactory(string connectionString) { _connectionString = connectionString; } public IDbConnection CreateConnection() { var conn = new SqlConnection(_connectionString); // 这里可以统一设置连接的属性,比如超时、编码之类的 // 也可以选择在这里打开连接,或者让调用者自己打开,看你的需求 conn.Open(); return conn; } }
然后在根MVC项目的Startup.cs里注册:
public void ConfigureServices(IServiceCollection services) { var connectionString = Configuration.GetConnectionString("YourDatabase"); services.AddSingleton<IDbConnectionFactory>(new SqlServerConnectionFactory(connectionString)); services.AddScoped<IProductRepository, ProductRepository>(); }
最后在仓储类里注入这个工厂:
public class ProductRepository : IProductRepository { private readonly IDbConnectionFactory _connectionFactory; public ProductRepository(IDbConnectionFactory connectionFactory) { _connectionFactory = connectionFactory ?? throw new ArgumentNullException(nameof(connectionFactory)); } public async Task DeleteProduct(int id) { using (var conn = _connectionFactory.CreateConnection()) { // 执行删除逻辑... } } }
这个方案把连接的创建逻辑完全封装起来,仓储不需要关心连接的细节,适合大型项目或者有复杂连接管理需求的场景。
内容的提问来源于stack exchange,提问作者Nelson Sousa
相关产品推荐
相关产品推荐

