简体   繁体   中英

How to use Dependency Injection on a application class in .Net Core for an Entity Framework Pooled Context to achieve multi-tenant implementation?

I have implemented an application which makes use of.Net Core 3.1 and Entity Framework.

The application uses entity framework dbcontext pooling, utilizing the Pomelo mysql ef library.

services.AddDbContextPool<myDbContext>(
            options => options
                .UseMySql(Configuration.GetConnectionString("DefaultConnection"),
                mysqlOptions =>
                {
                    mysqlOptions.MaxBatchSize(MySqlConfig.EfBatchSize);
                    mysqlOptions.EnableRetryOnFailure();
                    if (MySqlConfig.EfRetryOnFailure > 0)
                    {
                        mysqlOptions.EnableRetryOnFailure(MySqlConfig.EfRetryOnFailure, TimeSpan.FromSeconds(5), null);
                    }
                }
        ).UseLoggerFactory(consoleLoggerFactory));

What is important to note is the use of the AddDbContextPool Please see here: https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.dependencyinjection.entityframeworkservicecollectionextensions.adddbcontextpool?view=efcore-3.1

When using Context Pooling, your application is required to have a single constructor with DbContextOptions. ie: I cannot inject another object (in my case, I need a application service class for listing allowed tenants, and other claims related logic...) into this class, otherwise pooling cannot be used.

public myDbContext(DbContextOptions<myDbContext> options)
            : base(options)
        {
        }

Another caveat is that I utilize the HttpContextAccessor to access the claims on the User which is authenticated, which include the Tenants allowed to be accessed by that user which of course is accessed via Dependency Injection as well. The Authentication and Claims are retrieved via openid ultimately retrieving claims as Active Directory Groups, so I do not and would not have this info in the DB either as it originates from Active Directory...

The guts of this question is really, how can i access the HttpContext within my DbContext in order to implement a global filter for multi-tenant support in my application, and still use the DB Context Pooling.

I can achieve this by removing pooling, and make use of DI as normal via the constructor, but that is not what i'm after. I need to keep pooling, and implement the multi-tenant feature.

First, if your tenants are in different databases, DbContext pooling simply won't work. After a DbContext has been opened, it's connected to a single database. It's a minor performance feature, so it's not a great loss.

If you're setting query filters, you can probably make it work by simply not directly injecting a DbContext into your controllers, instead injecting a pre-configured bundle of services. And this also lets you centralize the code to rreconfigure the DbContext for the current tenant. EG:

public class ServiceContext 
{
    MyDbContext dbContext;
    HttpContext httpContext;
    IConfiguration config;
    public ServiceContext(MyDbContext dbContext, IHttpContextAccessor httpContextAccessor, IConfiguration config)
    {
        this.dbContext = dbContext;
        this.httpContext = httpContextAccessor.HttpContext;
        this.config = config;
        //use the httpContext to reconfigure the DbContext for single-tenant access
    }

    public HttpContext HttpContext { get => httpContext; set => throw new NotImplementedException(); }
    public MyDbContext DbContext { get => dbContext; }
    public IConfiguration Configuration { get => config; }

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM