Open Closed

Exception in OpenIdDict TokenCleanupBackgroundWorker with Oracle Devart Driver: Transaction isolation level RepeatableRead not supported. #6741


User avatar
0
wazbek created

Check the docs before asking a question: https://docs.abp.io/en/commercial/latest/ Check the samples to see the basic tasks: https://docs.abp.io/en/commercial/latest/samples/index The exact solution to your question may have been answered before, and please first use the search on the homepage. Provide us with the following info:

  • ABP Framework version: v8.0.3
  • UI Type: Angular
  • Database System: EF Core (Oracle) using the Devart driver
  • Tiered (for MVC) or Auth Server Separated (for Angular): Auth Server Separated (for Angular)
  • Exception message and full stack trace: [ERR] Transaction isolation level RepeatableRead not supported. System.ArgumentException: Transaction isolation level RepeatableRead not supported. at Devart.Data.Oracle.OracleTransaction..ctor(OracleConnection A_0, IsolationLevel A_1) at Devart.Data.Oracle.OracleConnection.BeginTransaction(IsolationLevel il) at Devart.Data.Oracle.OracleConnection.BeginDbTransaction(IsolationLevel isolationLevel) at Devart.Common.Entity.ct.BeginDbTransaction(IsolationLevel isolationLevel) at System.Data.Common.DbConnection.BeginDbTransactionAsync(IsolationLevel isolationLevel, CancellationToken cancellationToken) --- End of stack trace from previous location --- at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.BeginTransactionAsync(IsolationLevel isolationLevel, CancellationToken cancellationToken) at Volo.Abp.Uow.EntityFrameworkCore.UnitOfWorkDbContextProvider1.CreateDbContextWithTransactionAsync(IUnitOfWork unitOfWork) at Volo.Abp.Uow.EntityFrameworkCore.UnitOfWorkDbContextProvider1.CreateDbContextAsync(IUnitOfWork unitOfWork) at Volo.Abp.Uow.EntityFrameworkCore.UnitOfWorkDbContextProvider1.CreateDbContextAsync(IUnitOfWork unitOfWork, String connectionStringName, String connectionString) at Volo.Abp.Uow.EntityFrameworkCore.UnitOfWorkDbContextProvider1.GetDbContextAsync() at Volo.Abp.Domain.Repositories.EntityFrameworkCore.EfCoreRepository2.GetDbSetAsync() at Volo.Abp.Domain.Repositories.EntityFrameworkCore.EfCoreRepository2.GetQueryableAsync() at Volo.Abp.OpenIddict.Tokens.EfCoreOpenIddictTokenRepository.PruneAsync(DateTime date, CancellationToken cancellationToken) at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo) at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue1.ProceedAsync() at Volo.Abp.Uow.UnitOfWorkInterceptor.InterceptAsync(IAbpMethodInvocation invocation) at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed) at Volo.Abp.OpenIddict.Tokens.AbpOpenIddictTokenStore.PruneAsync(DateTimeOffset threshold, CancellationToken cancellationToken) at Volo.Abp.OpenIddict.Tokens.TokenCleanupService.CleanAsync()
  • Steps to reproduce the issue: The issue is happening in this code when the TokenCleanupBackgroundWorker runs:


3 Answer(s)
  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    You can override these methods to use another IsolationLevel, I will make it configurable in the next version.

    Your question credit has been refunded.

  • User Avatar
    0
    wazbek created

    hi @maliming

    What is the best way to override them?

    Thanks.

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    public override void ConfigureServices(ServiceConfigurationContext context)
    {
        context.Services.AddOpenIddict()
            .AddCore(builder =>
            {
                builder
                    .AddApplicationStore<MyAbpOpenIddictApplicationStore>()
                    .AddAuthorizationStore<MyAbpOpenIddictAuthorizationStore>()
                    .AddTokenStore<MyAbpOpenIddictTokenStore>();
            });
    }
    
    
    public class MyAbpOpenIddictApplicationStore : AbpOpenIddictApplicationStore
    {
        public MyAbpOpenIddictApplicationStore(IOpenIddictApplicationRepository repository,
            IUnitOfWorkManager unitOfWorkManager, IOpenIddictTokenRepository tokenRepository, IGuidGenerator guidGenerator,
            AbpOpenIddictIdentifierConverter identifierConverter,
            IOpenIddictDbConcurrencyExceptionHandler concurrencyExceptionHandler) : base(repository, unitOfWorkManager,
            tokenRepository, guidGenerator, identifierConverter, concurrencyExceptionHandler)
        {
        }
    
        public async override ValueTask DeleteAsync(OpenIddictApplicationModel application, CancellationToken cancellationToken)
        {
            Check.NotNull(application, nameof(application));
    
            try
            {
                using (var uow = UnitOfWorkManager.Begin(requiresNew: true, isTransactional: true, isolationLevel: IsolationLevel.ReadCommitted))
                {
                    await TokenRepository.DeleteManyByApplicationIdAsync(application.Id, cancellationToken: cancellationToken);
    
                    await Repository.DeleteAsync(application.Id, cancellationToken: cancellationToken);
    
                    await uow.CompleteAsync(cancellationToken);
                }
            }
            catch (AbpDbConcurrencyException e)
            {
                Logger.LogException(e);
                await ConcurrencyExceptionHandler.HandleAsync(e);
                throw new OpenIddictExceptions.ConcurrencyException(e.Message, e.InnerException);
            }
        }
    }
    
    public class MyAbpOpenIddictAuthorizationStore : AbpOpenIddictAuthorizationStore
    {
        public MyAbpOpenIddictAuthorizationStore(IOpenIddictAuthorizationRepository repository,
            IUnitOfWorkManager unitOfWorkManager, IGuidGenerator guidGenerator,
            IOpenIddictApplicationRepository applicationRepository, IOpenIddictTokenRepository tokenRepository,
            AbpOpenIddictIdentifierConverter identifierConverter,
            IOpenIddictDbConcurrencyExceptionHandler concurrencyExceptionHandler) : base(repository, unitOfWorkManager,
            guidGenerator, applicationRepository, tokenRepository, identifierConverter, concurrencyExceptionHandler)
        {
        }
    
        public async override ValueTask DeleteAsync(OpenIddictAuthorizationModel authorization, CancellationToken cancellationToken)
        {
            Check.NotNull(authorization, nameof(authorization));
    
            try
            {
                using (var uow = UnitOfWorkManager.Begin(requiresNew: true, isTransactional: true, isolationLevel: IsolationLevel.ReadCommitted))
                {
                    await TokenRepository.DeleteManyByAuthorizationIdAsync(authorization.Id, cancellationToken: cancellationToken);
    
                    await Repository.DeleteAsync(authorization.Id, cancellationToken: cancellationToken);
    
                    await uow.CompleteAsync(cancellationToken);
                }
            }
            catch (AbpDbConcurrencyException e)
            {
                Logger.LogException(e);
                await ConcurrencyExceptionHandler.HandleAsync(e);
                throw new OpenIddictExceptions.ConcurrencyException(e.Message, e.InnerException);
            }
        }
    
        public async override ValueTask<long> PruneAsync(DateTimeOffset threshold, CancellationToken cancellationToken)
        {
            using (var uow = UnitOfWorkManager.Begin(requiresNew: true, isTransactional: true, isolationLevel: IsolationLevel.ReadCommitted))
            {
                var date = threshold.UtcDateTime;
                var count = await Repository.PruneAsync(date, cancellationToken: cancellationToken);
                await uow.CompleteAsync(cancellationToken);
                return count;
            }
        }
    
    }
    
    public class MyAbpOpenIddictTokenStore : AbpOpenIddictTokenStore
    {
        public MyAbpOpenIddictTokenStore(IOpenIddictTokenRepository repository, IUnitOfWorkManager unitOfWorkManager,
            IGuidGenerator guidGenerator, IOpenIddictApplicationRepository applicationRepository,
            IOpenIddictAuthorizationRepository authorizationRepository,
            AbpOpenIddictIdentifierConverter identifierConverter,
            IOpenIddictDbConcurrencyExceptionHandler concurrencyExceptionHandler) : base(repository, unitOfWorkManager,
            guidGenerator, applicationRepository, authorizationRepository, identifierConverter, concurrencyExceptionHandler)
        {
        }
    
        public async override ValueTask<long> PruneAsync(DateTimeOffset threshold, CancellationToken cancellationToken)
        {
            using (var uow = UnitOfWorkManager.Begin(requiresNew: true, isTransactional: true, isolationLevel: IsolationLevel.ReadCommitted))
            {
                var date = threshold.UtcDateTime;
                var count = await Repository.PruneAsync(date, cancellationToken: cancellationToken);
                await uow.CompleteAsync(cancellationToken);
                return count;
            }
        }
    }
    
Made with ❤️ on ABP v8.2.0-preview Updated on March 25, 2024, 15:11