我有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个请求。并且,在这种情况下,我得到关于的错误:
连接未关闭。连接的当前状态是连接
我理解多线程的问题。应用程序启动时会创建一次JwtMessageHandler
。所以,我把这行:
_userService = (IUserService)_serviceProvider.GetService(typeof(IUserService));
inside方法,在它位于构造函数中之前。但是,它没有任何帮助。另外,我尝试在方法结束时将null设置为_userService
。
在这种情况下如何正确使用?
答案 0 :(得分:9)
尝试使用已经“连接”的连接 - 明确某些竞争条件的迹象。
IUserService
是否已注册“scope”生命周期,以及所有依赖项(userManager,dbContext)IServiceProvider
作为基于范围的服务解析 - 它与当前请求范围无关,并从“其他某个Universe”返回实例。使用HttpContext.RequestServices
进行服务解析。JwtMessageHandler
个实例是每个应用一个/单个。所以不要使用它的属性来存储_userService
(删除private IUserService _userService
)。相反,请在OnMessageReceived
(var _userService = ...
)。您已经检查过(1),(2)和(3)。我认为(4)是你需要修复bug的最后一个。
答案 1 :(得分:0)
我做了类似
的事情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);
}
答案 2 :(得分:0)
我经常面对这种情况。 我一直都是通过使用lock关键字来获得的。
lock (_context)
{
var user = _context.users.first(x => x.Id == userId);
}
这将锁定当前线程的对象(即_context)的使用,并且其他线程无法同时访问同一实例,因此没有任何问题。