我们似乎已经做了一些事情来向我们的应用程序引入某种线程问题。它是一个使用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 用
- 重新检查IUserService是否已注册&#34;范围&#34;生命周期及其所有依赖关系(userManager,dbContext)
- 不要使用在应用启动期间获得的IServiceProvider来进行基于范围的服务解析 - 它与当前请求范围无关,并且来自&#34;其他一些宇宙&#34;。使用HttpContext.RequestServices进行服务解析。
- 检查你是否等待&#34;等等。所有异步方法。如果你在仍然执行第一个请求时启动第二个请求 - 你可能会&#34;赶上&#34; dbContext期间&#34;连接&#34;阶段。
- 您的JwtMessageHandler实例是每个应用一个/单个。因此,不要使用它的属性来存储_userService(删除私有IUserService _userService)。相反,在OnMessageReceived(var _userService = ...)。
中使用局部变量 醇>
据我所知,我们并未遇到任何这些问题,几乎所有服务都是Scoped或Transient。
我们在应用启动期间使用async
来解析数据库以运行迁移,但不会超出此范围。
我认为await
可能没有{{1}},但我似乎无法找到它,我们也不会获取编译器警告。