私はjwt認証を持っています:
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
は、リクエストごとに呼び出されます。サーバーへのページに1つのリクエストがある場合、または1〜2秒待ってから何かを実行すると、すべて正常に機能します。しかし、サーバーに2〜3の同時リクエストを行うページがいくつかあります。そして、この場合、私は以下についてエラーを受け取ります:
接続は閉じられませんでした。接続の現在の状態は接続中です
マルチスレッドの問題を理解しています。 JwtMessageHandler
は、アプリケーションの起動時に1回作成されます。だから、私は次のように言います:
_userService = (IUserService)_serviceProvider.GetService(typeof(IUserService));
コンストラクターに配置される前のメソッド内。しかし、それは役に立ちませんでした。また、メソッドの最後でnullを_userService
に設定しようとしました。
この場合、正しく使用するにはどうすればよいですか?
すでに「接続」している接続を使用しようとしています-競合状態の明らかな兆候です。
IUserService
が「スコープ」の有効期間に登録されていること、およびすべての依存関係(userManager、dbContext)も再確認してくださいIServiceProvider
をスコープベースのサービスの解決に使用しないでください。これは、現在のリクエストスコープとは関係がなく、「他のユニバース」からのインスタンスを返します。サービスの解決にはHttpContext.RequestServices
を使用します。JwtMessageHandler
インスタンスはアプリごとに1つ/単一です。したがって、_userService
を格納するためにそのプロパティを使用しないでください(private IUserService _userService
を削除してください)。代わりに、OnMessageReceived
(var _userService = ...
)内のローカル変数を使用してください。すでに(1)、(2)、(3)をチェックしました。 (4)はバグを修正するために必要な最後のものだと思います。
@Dmitryの答えは私を正しい方向に向けました。私の場合、この問題は.NETCOREのミドルウェアで発生していました。私にとってこの問題を解決したのは、ミドルウェアの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);
}
私はこの状況に何度も直面しました。私はいつもlockキーワードを使ってやってきた。
lock (_context)
{
var user = _context.users.first(x => x.Id == userId);
}
これにより、現在のスレッドに対するオブジェクト(つまり、_context)の使用がロックされ、他のスレッドがこの同じインスタンスに同時にアクセスすることはできないため、問題は発生しません。