使用.NET6 Razor Pages多次刷新页面报连接未关闭错误如何解决

问题根因
该错误是ADO.NET连接池资源泄漏的典型表现,在.NET 6 Razor Pages项目中,快速刷新触发该问题的核心原因是数据库连接或EF Core上下文未被正确释放,短时间高频请求占满连接池后,新请求获取到状态异常的未回收连接实例,就会抛出该异常。
修复步骤
- 排查所有手动创建数据库连接的代码:所有调用
Open()的连接实例必须用using声明包裹,禁止仅在逻辑末尾手动调用Close()释放——一旦执行逻辑中途抛出异常,连接会直接泄漏永远无法回到连接池。
正确写法参考:// 错误实现:异常时连接无法释放 var conn = new SqlConnection(builder.Configuration.GetConnectionString("Default")); conn.Open(); var result = conn.QueryFirstOrDefault("SELECT TOP 1 Id FROM Articles"); conn.Close(); // 正确实现:using块会在代码执行结束(哪怕抛异常)时自动释放连接 using var conn = new SqlConnection(builder.Configuration.GetConnectionString("Default")); conn.Open(); var result = conn.QueryFirstOrDefault("SELECT TOP 1 Id FROM Articles"); - 检查EF Core生命周期配置:.NET 6 Razor Pages默认通过
AddDbContext注册的上下文是Scoped(请求级)生命周期,不要手动将DbContext注册为单例,也不要在单例生命周期的服务中直接注入Scoped的DbContext,否则上下文实例会跨请求复用,连接状态会被并发请求改乱。如果必须在单例服务中操作数据库,通过IServiceScopeFactory手动创建作用域获取上下文:public class SingletonCacheService { private readonly IServiceScopeFactory _scopeFactory; public SingletonCacheService(IServiceScopeFactory scopeFactory) { _scopeFactory = scopeFactory; } public async Task<Article> GetTopArticle() { using var scope = _scopeFactory.CreateScope(); var dbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>(); return await dbContext.Articles.OrderBy(a=>a.Id).FirstOrDefaultAsync(); } } - 修正异步代码的错误写法:所有数据库相关的异步方法调用必须加
await,禁止用.Result、.Wait()同步阻塞异步调用,.NET 6中同步阻塞数据库异步调用极易造成连接状态错乱,高频刷新时就会触发连接未关闭错误。 - 兜底优化连接配置:在数据库连接字符串中添加
Max Pool Size=100;Connection Lifetime=30;参数,限制连接池最大容量、自动回收闲置超过30秒的连接,避免短时间并发打满连接池。注意该配置仅为兜底方案,核心还是要修复代码层面的连接泄漏问题。 - 修正Kestrel配置避免请求中断导致的资源泄漏:快速刷新时客户端会主动断开未完成的请求,如果服务端没有适配请求终止的场景,可能会跳过连接回收逻辑。在Program.cs中添加如下配置:
builder.WebHost.ConfigureKestrel(options => { options.Limits.MaxConcurrentConnections = 100; options.Limits.RequestHeadersTimeout = TimeSpan.FromSeconds(15); options.AllowSynchronousIO = false; });
验证方式
修复完成后,模拟50以上并发持续请求对应页面1-2分钟,若不再抛出该错误,说明连接泄漏问题已解决。
内容的提问来源于stack exchange,提问作者Alexandru Petre
相关产品推荐
相关产品推荐

