EF。 连接没有关闭。 连接的当前状态是连接
我有jwt auth:
var messageHandlers = new JwtMessageHandler(_serviceProvider); app.UseJwtBearerAuthentication(new JwtBearerOptions { AutomaticAuthenticate = true, AutomaticChallenge = true, Events = new JwtBearerEvents { OnMessageReceived = messageHandlers.OnMessageReceived, }, TokenValidationParameters = tokenValidationParameters });
JwtMessageHandler
是我的自定义处理程序。 在处理程序中,我必须对数据库进行一些查询,因此我传递ServiceProvider
并解析我的用户服务:
public class JwtMessageHandler { private IUserService _userService; public async Task OnMessageReceived(MessageReceivedContext arg) { //parsing header, get claims from token ... _userService = (IUserService)arg.HttpContext.RequestServices.GetService(typeof(IUserService)); var isRoleChanged = await _userService.IsRoleChanged(tokenObject.Subject, rolesFromToken); if (isRoleChanged) { GenerateBadResponse(arg); return; } var canLogin = await _userService.CanLogin(tokenObject.Subject); if (!canLogin) { GenerateBadResponse(arg); return; } } }
在服务中我提出查询:
... var user = await _userManager.FindByEmailAsync(email); var currentRoles = await _userManager.GetRolesAsync(user); ..
为每个请求调用OnMessageReceived
。 当我在服务器页面上有一个请求或我在做某事之前等待一两秒钟一切正常。 但是,我有几个页面,我同时向服务器发出2-3个请求。 并且,在这种情况下,我得到错误:
连接没有关闭。 连接的当前状态是连接
我理解multithreading的问题。 应用程序启动时,会创建一次JwtMessageHandler
。 所以,我把这条线:
_userService = (IUserService)_serviceProvider.GetService(typeof(IUserService));
inside方法,在它位于构造函数中之前。 但是,它没有帮助。 另外,我尝试在方法的最后将null设置为_userService
。
在这种情况下如何正确使用?
尝试使用已经“连接”的连接 – 清楚某些竞争条件的迹象。
- 重新检查
IUserService
是否已注册“scope”生命周期,以及所有依赖项(userManager,dbContext) - 不要使用在应用程序启动期间获得的
IServiceProvider
来进行基于范围的服务解析 – 它与当前请求范围无关,并且从“其他某个Universe”返回实例。 使用HttpContext.RequestServices
进行服务解析。 - 检查您是否“等待”所有异步方法。 如果在仍然执行第一个请求时启动第二个请求 – 您可能在“连接”阶段“捕获”dbContext。
- 您的
JwtMessageHandler
实例是每个应用程序一个/单个。 所以不要使用它的属性来存储_userService
(删除private IUserService _userService
)。 相反,在var _userService = ...
(var _userService = ...
)中使用局部变量。
您已经检查过(1),(2)和(3)。 我认为(4)是你需要修复bug的最后一个。
@Dmitry的回答指出了我正确的方向。 对我来说,我在.NETCORE的MiddleWare中遇到了这个问题。 为我解决这个问题的是在我的中间件的Invoke方法中解析IUnitOfWork接口。
我做了类似的事情
public Task Invoke(HttpContext context) { _unitOfWork = (IUnitOfWork)context.RequestServices.GetService(typeof(IUnitOfWork)); //Some checks var apiKey = context.Request.Headers["X-ApiKey"][0]; var clientApp = _unitOfWork.ClientApplicationsRepository.Items.FirstOrDefault(s => s.ApiKey == apiKey); //Some other code... return _next(context); }