Open Closed

System.ObjectDisposedException: Cannot access a disposed context instance #1753


User avatar
1
Mohammad created

Hello

I am getting this error when I try to use a EF Core Repository which is resolved using ServiceProvider in CustomTenantResolver.

System.ObjectDisposedException: Cannot access a disposed context instance. A common cause of this error is disposing a context instance that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application. This may occur if you are calling 'Dispose' on the context instance, or wrapping it in a using statement. If you are using dependency injection, you should let the dependency injection container take care of disposing context instances.

Thanks

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, please use the search on the homepage.

If you're creating a bug/problem report, please include followings:

  • ABP Framework version: v4.3.2
  • UI type: Angular
  • DB provider: EF Core
  • Tiered (MVC) or Identity Server Separated (Angular): yes
  • Exception message and stack trace:
  • Steps to reproduce the issue:"

8 Answer(s)
  • User Avatar
    0
    EngincanV created
    Support Team .NET Developer

    Hi @Mohammad, can you share where you used the repository (for example, your application service method)?

  • User Avatar
    0
    Mohammad created

    Hi

    I am using it in Custom Tenant Resolver.

     public class AccessTokenTenantResolver : HttpTenantResolveContributorBase
        {
            public override string Name => "AccessToken";
    
    
    
            protected override async Task<string> GetTenantIdOrNameFromHttpContextOrNullAsync(ITenantResolveContext context, HttpContext httpContext)
            {
               
    
                IClientCredentialRepository clientCredentialRepository = context.ServiceProvider.GetRequiredService<IClientCredentialRepository>();
    
                string accessCode = httpContext.Request.Headers["Authorization"];
    
                if (!string.IsNullOrEmpty(accessCode))
                {
                    var token = accessCode.Split(" ")[1];
                    var tokenHandler = new JwtSecurityTokenHandler();
                    var tokens = tokenHandler.ReadJwtToken(token);
                    var client_id = tokens.Claims.FirstOrDefault(x => x.Type == "client_id").Value;
                    var scopes = tokens.Claims.FirstOrDefault(x => x.Type == "scope").Value;
    
                    if (scopes.Contains("Scope"))
                    {
                        var client = await clientCredentialRepository.SingleOrDefaultAsync(x => x.ClientId == client_id);
    
                        if (client == null)
                            return await Task.FromResult<string>(null);
    
                       
                        return await Task.FromResult(client.TenantId.Value.ToString());
                    }
                }
    
                return await Task.FromResult("37fb7b60-0ba6-8109-70b1-a049e5f25575");
            }
        }
    
  • User Avatar
    0
    EngincanV created
    Support Team .NET Developer

    Can you add the [UnitOfWork] attribute to above of your method and try it again?

  • User Avatar
    0
    Mohammad created

    I am getting the same error even after adding [UnitOfWork]

    2021-08-23 16:01:08.732 +03:00 [WRN] System.ObjectDisposedException: Cannot access a disposed context instance. A common cause of this error is disposing a context instance that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application. This may occur if you are calling 'Dispose' on the context instance, or wrapping it in a using statement. If you are using dependency injection, you should let the dependency injection container take care of disposing context instances.
    Object name: 'ClientManagementDbContext'.
       at Microsoft.EntityFrameworkCore.DbContext.CheckDisposed()
       at Microsoft.EntityFrameworkCore.DbContext.get_InternalServiceProvider()
       at Microsoft.EntityFrameworkCore.DbContext.get_ChangeTracker()
       at Microsoft.EntityFrameworkCore.Query.CompiledQueryCacheKeyGenerator.GenerateCacheKeyCore(Expression query, Boolean async)
       at Microsoft.EntityFrameworkCore.Query.RelationalCompiledQueryCacheKeyGenerator.GenerateCacheKeyCore(Expression query, Boolean async)
       at Npgsql.EntityFrameworkCore.PostgreSQL.Query.Internal.NpgsqlCompiledQueryCacheKeyGenerator.GenerateCacheKey(Expression query, Boolean async)
       at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.ExecuteAsync[TResult](Expression query, CancellationToken cancellationToken)
       at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.ExecuteAsync[TResult](Expression expression, CancellationToken cancellationToken)
       at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ExecuteAsync[TSource,TResult](MethodInfo operatorMethodInfo, IQueryable`1 source, Expression expression, CancellationToken cancellationToken)
       at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ExecuteAsync[TSource,TResult](MethodInfo operatorMethodInfo, IQueryable`1 source, LambdaExpression expression, CancellationToken cancellationToken)
       at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.SingleOrDefaultAsync[TSource](IQueryable`1 source, Expression`1 predicate, CancellationToken cancellationToken)
       at Zenithr.Tenant.Shared.AccessTokenTenantResolver.GetTenantIdOrNameFromHttpContextOrNullAsync(ITenantResolveContext context, HttpContext httpContext) in C:\websites\ZENITHR3.0\Zenithr.Shared.Tenant\AccessTokenTenantResolver.cs:line 43
       at Volo.Abp.AspNetCore.MultiTenancy.HttpTenantResolveContributorBase.ResolveFromHttpContextAsync(ITenantResolveContext context, HttpContext httpContext)
       at Volo.Abp.AspNetCore.MultiTenancy.HttpTenantResolveContributorBase.ResolveAsync(ITenantResolveContext context)
    
  • User Avatar
    1
    maliming created
    Support Team Fullstack Developer

    hi Mohammad

    Can you try this:

    using (var uow = _unitOfWorkManager.Begin()
    {
        var client = await clientCredentialRepository.SingleOrDefaultAsync(x => x.ClientId == client_id);
        await uow.CompleteAsync();
    }
    
    
  • User Avatar
    1
    Mohammad created

    the using statement worked.

    Why do I need to do the using for Unitofwork for the repository to work? can you explain? Is this a workaround or an actual solution?

  • User Avatar
    1
    maliming created
    Support Team Fullstack Developer

    hi

    The GetTenantIdOrNameFromHttpContextOrNullAsync method not in a uow because the middleware order.

    And the AccessTokenTenantResolver is created by new instead of DI, so the [UnitOfWork] won't work

    In this case you need to create uow manually.

  • User Avatar
    0
    Mohammad created

    Thanks for the Explaination and refund.

Made with ❤️ on ABP v8.2.0-preview Updated on March 25, 2024, 15:11