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

依赖注入下IDbConnection/SqlConnection偶发ConnectionString未初始化异常排查

解决偶发的System.InvalidOperationException: 'The ConnectionString property has not been initialized.'异常

我来帮你定位这个偶发异常的核心问题——它其实是DI生命周期不匹配+错误的连接Dispose方式导致的:

你把IDbConnection注册为Transient(每次注入都会生成新实例),但你的EmployeeRepository是Scoped的(同一个HTTP请求内只会创建一次Repository实例)。这意味着:同一个请求里,Repository拿到的IDbConnection实例会跟着它存活整个请求周期。但你在GetAllActiveEmployees里写了using (var db = _connection)——这行代码会直接把注入进来的_connection实例给Dispose掉!

如果在同一个请求里,这个Repository的其他方法(或者同一个方法被多次调用)再去使用_connection,就会因为连接已经被释放、内部状态被重置,从而抛出ConnectionString未初始化的异常。这就是为什么异常是偶发的——只有当请求内出现多次复用Repository实例的场景时才会触发。

两种可行的解决方案

方案1:使用连接工厂(推荐,最规范)

不要直接注入IDbConnection,而是注入一个可以创建新连接的工厂方法,这样每次需要连接时都能拿到全新的实例,用完自动Dispose:

  1. 先修改DI注册代码:
public void ConfigureServices(IServiceCollection services) 
{ 
    // 注册连接工厂,每次调用都会生成新的SqlConnection实例
    services.AddTransient<Func<IDbConnection>>(() => 
        () => new SqlConnection(Configuration.GetConnectionString("AppConnectionString"))); 
    
    // 其他服务注册保持不变
    services.AddScoped<IAppConfigurationRepository, AppConfigurationRepository>(); 
    services.AddScoped<IHomeworkingRequestRepository, HomeworkingRequestRepository>(); 
    services.AddScoped<IEmployeeRepository, EmployeeRepository>(); 
    services.AddScoped<IEmployeeService, EmployeeService>(); 
    services.AddScoped<IHomeworkingRequestService, HomeworkingRequestService>(); 
    services.AddMvc(); 
}
  1. 然后调整EmployeeRepository的实现:
public class EmployeeRepository : IEmployeeRepository 
{ 
    private readonly Func<IDbConnection> _connectionFactory; 

    // 注入连接工厂,而不是直接注入连接
    public EmployeeRepository(Func<IDbConnection> connectionFactory) 
    { 
        _connectionFactory = connectionFactory; 
    } 

    public IEnumerable<Employee> GetAllActiveEmployees() 
    { 
        string query = @" 
            SELECT FirstName 
                   ,LastName 
                   ,BusinessUnit 
            FROM Employees"; 
        
        // 每次调用都创建新连接,using会自动释放资源
        using (var db = _connectionFactory()) 
        { 
            db.Open(); 
            return db.Query<Employee>(query); 
        } 
    } 
}

方案2:避免Dispose注入的连接(不推荐,有资源隐患)

如果你暂时不想改DI注册,那可以去掉Repository里的using语句——因为注入的连接会在请求结束时由DI容器自动释放:

public IEnumerable<Employee> GetAllActiveEmployees() 
{ 
    string query = @" 
        SELECT FirstName 
               ,LastName 
               ,BusinessUnit 
        FROM Employees"; 
    
    _connection.Open(); 
    return _connection.Query<Employee>(query); 
}

但这个方案有明显隐患:如果请求内多次调用Repository的方法,会重复调用Open()导致异常,而且连接资源不能及时释放,可能引发连接池耗尽的问题。

为什么之前改Transient能暂时解决?

之前改成Transient时,你的请求流程里可能每个Repository方法只被调用一次,Dispose连接后没有后续复用的场景。但当业务逻辑变化,同一个请求内需要多次调用Repository方法时,就会触发这个偶发异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 03:59:37