EntityFrameworkCore - 诊断"连接未关闭。连接的当前状态已打开。"

时间:2017-10-26 14:24:45

标签: async-await .net-core entity-framework-core

我们似乎已经做了一些事情来向我们的应用程序引入某种线程问题。它是一个使用EntityFrameworkCore的dotnet核心1.1.2应用程序。间歇性地,但可重复地,我们将得到以下错误之一:

  

System.InvalidOperationException:'连接未关闭。连接的当前状态是开放的。'运行EF查询时出现异常。

  

System.InvalidCastException:'无法转换类型' System.Data.ProviderBase.DbConnectionClosedConnecting'输入' System.Data.SqlClient.SqlInternalConnectionTds'。'

  

System.ObjectDisposedException:'无法访问已处置的对象。此错误的常见原因是处理从依赖项注入解析的上下文,然后尝试在应用程序的其他位置使用相同的上下文实例。如果您在上下文中调用Dispose()或将上下文包装在using语句中,则可能会发生这种情况。如果使用依赖注入,则应该让依赖注入容器处理上下文实例。'

这种情况几乎可以在应用程序的任何一点发生,但这种方法似乎是最常见的罪魁祸首(这种情况经常被调用):

public class WidgetConfigurationRepository : IWidgetConfigurationRepository
{

    public WidgetConfigurationRepository(LocalContext dataContext)
    {
        Context = dataContext ?? throw new ArgumentNullException(nameof(dataContext));
    }

    private LocalContext _context { get; private set; }

    public async Task<WidgetConfiguration> LoadConfigurationAsync(Guid widgetId)
    {
        return await _context.WidgetConfigurations
            .Include(x => x.Options)
            .FirstOrDefaultAsync(x => x.WidgetId.Equals(widgetId));
    }
...
}

存储库是通过Core DI容器创建的,并在运行时注入:

services.AddScoped<IWidgetConfigurationRepository, WidgetConfigurationRepository>();

Repository和LocalContext都注册为Scoped,并且没有LocalContext的Singleton访问器。

遍历堆栈跟踪(和并行堆栈)显示每个async方法都是await,并且我已经使用实现替换了应用程序中的接口,希望尝试找到没有async的任何await

LocalContext本身是通过LocalDbContextFactory创建的,LocalContext也注册为Scoped。它从中央数据上下文读取数据,检查一些数据,然后实例化Task的新实例。正如预期的那样,每次请求只发生一次。

最终,我正在寻找一些帮助来解决可能导致此问题的原因,我们的应用程序现已相当庞大,而且我不确定是否可以提供足够的代码段来提供帮助。

目前,我认为我最好的选择是编写一个Roslyn分析器来遍历返回Task<T>ServiceProvider.GetService<>()的所有方法,并检查返回对象是否发生了某些事情,但是我&# 39;我想知道我是否有更容易错过的事情。

有一个相关问题:EF. The connection was not closed. The connection's current state is connecting

  
      
  1. 重新检查IUserService是否已注册&#34;范围&#34;生命周期及其所有依赖关系(userManager,dbContext)
  2.   
  3. 不要使用在应用启动期间获得的IServiceProvider来进行基于范围的服务解析 - 它与当前请求范围无关,并且来自&#34;其他一些宇宙&#34;。使用HttpContext.RequestServices进行服务解析。
  4.   
  5. 检查你是否等待&#34;等等。所有异步方法。如果你在仍然执行第一个请求时启动第二个请求 - 你可能会&#34;赶上&#34; dbContext期间&#34;连接&#34;阶段。
  6.   
  7. 您的JwtMessageHandler实例是每个应用一个/单个。因此,不要使用它的属性来存储_userService(删除私有IUserService _userService)。相反,在OnMessageReceived(var _userService = ...)。
  8. 中使用局部变量   

据我所知,我们并未遇到任何这些问题,几乎所有服务都是Scoped或Transient。

我们在应用启动期间使用async来解析数据库以运行迁移,但不会超出此范围。

我认为await可能没有{{1}},但我似乎无法找到它,我们也不会获取编译器警告。

0 个答案:

没有答案