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:

Markdown supported.
Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)

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.

    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
  • User Avatar
    0
    wazbek created

    hi @maliming

    What is the best way to override them?

    Thanks.

    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
  • 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;
            }
        }
    }
    
    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
Boost Your Development
ABP Live Training
Packages
See Trainings
Mastering ABP Framework Book
The Official Guide
Mastering
ABP Framework
Learn More
Mastering ABP Framework Book
Made with ❤️ on ABP v10.8.0-preview. Updated on September 28, 2026, 11:44
1
ABP Assistant
🔐 You need to be logged in to use the chatbot. Please log in first.