2

we are using ef core 3.1 And we want to use dynamic query filter, I tried sample implementation but did not work correctly we expected, filtering always same tenant id,i tried to explain at below


 public class TestDbContext : DbContext
    {
      
        public DbSet<TenantUser> TenantUsers { get; set; }
      

        private readonly ITenantProvider _tenantProvider;

        private Guid? TenantId => _tenantProvider.TenantId;

        public TestDbContext (DbContextOptions<TestDbContext > options, ITenantProvider tenantProvider) : base(options)
        {
               _tenantProvider = tenantProvider;
        }


        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<TenantUser>()
                .HasQueryFilter(p => EF.Property<Guid>(p, "TenantId") == TenantId);
        }

    }

ITenantProvider returns TenantId from HttpContext headers

this code filtering always same tenant id from coming first request

Update:


 public class TenantProvider : ITenantProvider
    {
        private readonly IHttpContextAccessor _httpContextAccessor;

        public TenantProvider(IHttpContextAccessor httpContextAccessor)
        {
            _httpContextAccessor = httpContextAccessor;
        }

        public Guid? TenantId
        {
            get
            {
                if (_httpContextAccessor.HttpContext.Request.Headers.TryGetValue(HeaderNames.TenantId, out var tenantId) &&
                    Guid.TryParse(tenantId, out Guid parsedTenantId))
                {
                    return parsedTenantId;
                }
                return null;
            }
        }
    }

For example First Request TenantId = 60000000-0000-0000-0000-000000000000 This filter => 60000000-0000-0000-0000-000000000000

Second Request TenantId = 10000000-0000-0000-0000-000000000000 This filter => 60000000-0000-0000-0000-000000000000

7
  • 1
    but did not work isn't a problem description. And this code filtering always same tenant id from coming first request sounds like the filter did work. It's _tenantProvider.TenantId that returns the same ID every time. Or you use the same DbContext every time (very bad idea) which means you always use the value stored in the TenantId field Commented Jun 3, 2021 at 11:15
  • Post the ITenantProvider code. This doesn't seem to be about EF Core Commented Jun 3, 2021 at 11:16
  • @PanagiotisKanavos added Commented Jun 3, 2021 at 11:23
  • 1
    Looks correct. Changing visibility of TenantId to public will not help? Commented Jun 3, 2021 at 11:32
  • But are you using a different DbContext instance? Or a singleton/pooled one? Commented Jun 3, 2021 at 11:32

2 Answers 2

4

You should also implement a custom IModelCacheKeyFactory

public class MyModelCacheKeyFactory : IModelCacheKeyFactory
{
    public object Create(DbContext context)
    {
        if (context is TestDbContext testDbContext)
        {
            return (context.GetType(), testDbContext.TenantId);
        }
        return context.GetType();
    }
}

And then, you need to replace like this

var builder = new DbContextOptionsBuilder<TestDbContext>();

builder.ReplaceService<IModelCacheKeyFactory, MyModelCacheKeyFactory>();

var context = new TestDbContext(builder.Options);

Reference: https://learn.microsoft.com/en-us/dotnet/api/microsoft.entityframeworkcore.infrastructure.imodelcachekeyfactory

Sign up to request clarification or add additional context in comments.

1 Comment

3

We tried something similar like that a few years ago. Main problem is here that OnModelCreating method only triggered once. So HasQueryFilter works once and gets the current tenant id from provider and it applies to all queries the same tenant id.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.