#c# #.net #asp.net-identity #identityserver4 #asp.net-core-3.1
#c# #.net #asp.net-идентификация #identityserver4 #asp.net-core-3.1
Вопрос:
Я использую ITicketStore в соответствии с этой статьей. При этом DbContext создается всякий раз, когда требуется выполнить какие-либо операции с базой данных.
В моем коде вместо создания DbContext с помощью синтаксиса() вводится через конструктор. Все работало нормально, пока код не был запущен в производство. Начал получать нижеприведенные исключения, когда трафик увеличился.
- Система.Исключение InvalidOperationException Вторая операция, запущенная в этом контексте до завершения предыдущей операции.
- Майкрософт.EntityFrameworkCore.Исключение DbUpdateConcurrencyException
Вероятно, это связано с тем, что ITicketStore является одноэлементным и вводит DbContext с использованием DI, который совместно использует один и тот же экземпляр DbContext между несколькими потоками.
Я изменил код для создания экземпляра DbContext с помощью функции(), и теперь он работает нормально.
Но я пытаюсь найти любой способ заставить DbContext работать, вводя через DI.
Комментарии:
1. Вы пропускаете какие-либо ожидания при вызовах, использующих dbcontext? Я вызвал контекст БД связкой без ожидания, потому что в конце у меня был WhenAll . Это вызвало аналогичную проблему.
2. нет, использование await при использовании dbcontext
Ответ №1:
Вот как я это сделал
//in Startup.cs ConfigureServices method
//I tried using the PostConfigure methods, but it didn't to work for me
services.TryAddEnumerable(ServiceDescriptor.Singleton<IPostConfigureOptions<CookieAuthenticationOptions>, PostConfigureCookieAuthenticationOptionsTicketStore>());
//This sets the store to the options.
public class PostConfigureCookieAuthenticationOptionsTicketStore : IPostConfigureOptions<CookieAuthenticationOptions>
{
private readonly SingletonTicketStore _store;
public PostConfigureCookieAuthenticationOptionsTicketStore(SingletonTicketStore store) => _store = store;
public void PostConfigure(string name, CookieAuthenticationOptions options) => options.SessionStore = _store;
}
//This implemenation is singleton compatible
public class SingletonTicketStore : ITicketStore
{
private readonly IServiceProvider _services;
public SingletonTicketStore(IServiceProvider services)
{
_services = services;
}
public async Task RemoveAsync(string key) => await WithScopeAsync(s => s.RemoveAsync(key));
public async Task RenewAsync(string key, AuthenticationTicket ticket) => await WithScopeAsync(s => s.RenewAsync(key, ticket));
public async Task<AuthenticationTicket> RetrieveAsync(string key) => await WithScopeAsync(s => s.RetrieveAsync(key));
public async Task<string> StoreAsync(AuthenticationTicket ticket) => await WithScopeAsync(s => s.StoreAsync(ticket));
private async Task WithScopeAsync(Func<ITicketStore, Task> action) => await WithScopeAsync(async t => { await action(t); return true; });
private async Task<T> WithScopeAsync<T>(Func<ITicketStore, Task<T>> action)
{
//This opens a new scope, allowing you to use scoped dependencies
using (var scope = _services.CreateScope())
{
//don't forget to await the result here, of stuff (dbcontext) could be disposed otherwise
return await action(scope.ServiceProvider.GetRequiredService<ITicketStore>());
}
}
}
public class ScopedTicketStore : ITicketStore
{
//your implementation
}
Надеюсь, это поможет 😉