首页 > 解决方案 > 使用多个参数注册 DbContext

问题描述

我正在尝试将 TenantProvider 注入 DbContext

public class AppDbContext : IdentityDbContext<ApplicationUser, ApplicationRole, long>
{
    public int? _tenantId;

    public ITenantProvider _tenantProvider;

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

但我不明白如何正确注册它 - 如果我将断点放在构造函数中 -tenantProvidernull.

一点来自Startup.cs

services.AddDbContext<AppDbContext>(options => AppDbContextOptionsBuilder.Get());

需要下一行将其注入DbContext控制器或服务(如果我将ServiceLifetime.Scoped作为第二个参数添加到上述方法 - AddDbContext- 该功能不起作用):

services.AddScoped(p => new AppDbContext(AppDbContextOptionsBuilder.Get(), p.GetService<ITenantProvider>()));

Entity Framework在我的解决方案中是一个单独的项目)


使用.AddScoped方法时 - 我们可以通过TenantProvider使用方法解析它来传递给构造函数.GetService

有谁知道如何解决TenantProvider方法.AddDbContext


附加信息:

我试图ITenantProvider在 with 的构造函数中DbContext替换IHttpContextAccessor- 后者被注册为单例。但acessor参数仍然是null

services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();

标签: entity-frameworkasp.net-coredependency-injectionentity-framework-coreinversion-of-control

解决方案


我真的不明白你的AddScoped电话应该做什么。AddDbContext将已经使用服务集合正确注册数据库上下文。所以当你通过依赖注入解析上下文时,额外的依赖会被自动解析。

所以这样做应该足够了:

services.AddDbContext<AppDbContext>(options => …);

services.AddSingleton<ITenantProvider, TenantProvider>();

然后,您可以依赖于AppDbContext使用构造函数注入,例如在您的控制器中。


有两个注意事项:

  1. 配置选项时,应修改传递的选项对象。所以你不应该只返回AppDbContextOptionsBuilder.Get(),而是使用传递的选项对象并编辑它。

  2. 您应该真正考虑您的数据库上下文依赖于您的租户提供者是否是正确的做法。根据SRP,您的数据库应该只做一件事情,那就是提供数据库访问。

    根据您的租户提供者如何影响您的数据库访问,将这种依赖关系上移一层到使用数据库上下文和租户提供者以正确方式查询数据的某些服务中可能更有意义。


推荐阅读