简体   繁体   English

如何在.Net Core中的应用程序class上使用依赖注入来实现实体框架池化上下文以实现多租户?

[英]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.我已经实现了一个使用 .Net Core 3.1 和 Entity Framework 的应用程序。

The application uses entity framework dbcontext pooling, utilizing the Pomelo mysql ef library.该应用程序使用实体框架 dbcontext 池,利用 Pomelo mysql ef 库。

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需要注意的是AddDbContextPool的使用请参见此处: 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.使用上下文池时,您的应用程序需要有一个带有 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.即:我不能将另一个 object (在我的情况下,我需要一个应用程序服务 class 来列出允许的租户,以及其他与索赔相关的逻辑......)到这个 class 中,否则不能使用池。

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.另一个需要注意的是,我使用 HttpContextAccessor 来访问经过身份验证的用户的声明,其中包括允许该用户访问的租户,当然也可以通过依赖注入访问。 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...身份验证和声明是通过 openid 检索的,最终将声明作为 Active Directory 组检索,因此我没有也不会在数据库中包含此信息,因为它源自 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.这个问题的实质是,我怎样才能访问我的 DbContext 中的 HttpContext 以便在我的应用程序中实现多租户支持的全局过滤器,并且仍然使用 DB 上下文池。

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.我可以通过删除池来实现这一点,并通过构造函数正常使用 DI,但这不是我所追求的。 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.首先,如果您的租户位于不同的数据库中,则 DbContext 池根本不起作用。 After a DbContext has been opened, it's connected to a single database.打开 DbContext 后,它会连接到单个数据库。 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.如果您正在设置查询过滤器,您可以通过简单地不直接将 DbContext 注入控制器来使其工作,而是注入预先配置的服务包。 And this also lets you centralize the code to rreconfigure the DbContext for the current tenant.这还允许您集中代码以重新配置当前租户的 DbContext。 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; }

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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