Есть ли какой-нибудь способ сделать ITicketStore ограниченным?

#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
    }

 

Надеюсь, это поможет 😉