【问题标题】:Autofac Multitenant Database ConfigurationAutofac 多租户数据库配置
【发布时间】:2018-10-01 15:59:31
【问题描述】:

我有一个基本的抽象上下文,它有几百个共享对象,然后是 2 个“实现”上下文,它们都从基础继承并被设计为供 .net 核心应用程序中的不同租户使用。一个租户对象被注入到 OnConfiguring 的构造函数中以获取要使用的连接字符串。

public abstract class BaseContext : DbContext
{
    protected readonly AppTenant Tenant;

    protected BaseContext (AppTenant tenant)
    {
        Tenant = tenant;
    }
}

public TenantOneContext : BaseContext
{
   public TenantOneContext(AppTenant tenant) 
        : base(tenant)
    {
    }
}

在 startup.cs 中,我像这样注册 DbContexts:

services.AddDbContext<TenantOneContext>();
services.AddDbContext<TenantTwoContext>();

然后使用 autofac 容器和 th Multitenant 包,我像这样注册特定于租户的上下文:

IContainer container = builder.Build();

MultitenantContainer mtc = new MultitenantContainer(container.Resolve<ITenantIdentificationStrategy>(), container);

mtc.ConfigureTenant("1", config =>
{
    config.RegisterType<TenantOneContext>().AsSelf().As<BaseContext>();
});

mtc.ConfigureTenant("2", config =>
{
    config.RegisterType<TenantTwoContext>().AsSelf().As<BaseContext>();
});

Startup.ApplicationContainer = mtc;

return new AutofacServiceProvider(mtc);

我的服务层是围绕被注入的 BaseContext 设计的,以便在可能的情况下重用,然后需要特定功能的服务使用 TenantContexts。

public BusinessService
{
   private readonly BaseContext _baseContext;

   public BusinessService(BaseContext context) 
   {
       _baseContext = context;
   }
}

在运行时的上述服务中,我得到一个异常“无法使用构造函数查找器'Autofac.Core.Activators.Reflection.DefaultConstructorFinder'找到类型'BaseContext'的构造函数”。我不知道为什么这被打破了...... AppTenant 肯定是创建的,因为我可以成功地将它注入其他地方。如果我添加一个额外的注册,我可以让它工作:

builder.RegisterType<TenantOneContext>().AsSelf().As<BaseContext>();

我不明白为什么租户容器注册需要上述注册才能工作。这对我来说似乎坏了;在结构映射(Saaskit)中,我能够在不添加额外注册的情况下做到这一点,并且我假设使用内置的 AddDbContext 注册将负责为要覆盖的容器创建默认注册。我是否在这里遗漏了什么,或者这可能是 autofac 的多租户功能中的错误?

更新:

这里是问题的完全可运行的 repo:https://github.com/danjohnso/testapp

如果我有第 53/54 行和第 82-90 行,为什么需要 Startup.cs 的第 66 行?

【问题讨论】:

  • 从这个解释中不清楚你在解决这个问题时在做什么以及正在创建哪些范围。请创建一个最小、完整和可验证的示例,如下所述:stackoverflow.com/help/mcve
  • AddDbConetxt(和常规注册)使用接受DbContextOptions/DbContextOptions&lt;T&gt;的构造函数。您是否尝试将您的构造函数重新声明为protected BaseContext (DbContextOptions options, AppTenant tenant) : base(options))
  • @Tseng 你可以,但是我需要使用 OnConfiguring 来覆盖上下文中的一些其他行为,这就是我说我正在使用它的原因。 alexander-leonov 不可能将整个应用程序分解为一个可运行的示例。我已经为熟悉 autofac 的人提供了所有正在使用的部分和相关代码的有效解释,以便为我提供有关此行为的一些指导
  • 你仍然可以这样做 iirc。在任何情况下都会调用OnConfiguring,无论您是否使用DbContextOptions 构造函数构造它。您可以在OnConfiguring 中使用IsConfigured 来查看它是否已通过DbContextOptions 进行配置。见remarks in the docs
  • @Dan - 发现问题,今晚将发布我的答案。回购实际上帮了很多忙。

标签: asp.net-core entity-framework-core autofac multi-tenant


【解决方案1】:

正如我所料,您的问题与多租户无关。你几乎完全正确地实现了它,你是对的,你不需要额外的注册,顺便说一句,这两个(下面)也是因为你稍后在租户的范围内注册它们:

        services.AddDbContext<TenantOneContext>();
        services.AddDbContext<TenantTwoContext>();

所以,您在TenantIdentitifcationStrategy 实现中只犯了一个很小但很重要的错误。让我们来看看你是如何创建容器的——这主要是为了其他可能遇到这个问题的人。我将仅提及相关部分。

首先,TenantIdentitifcationStrategy 与其他内容一起在容器中注册。由于没有明确的生命周期范围规范,默认情况下它被注册为InstancePerDependency()——但这并不重要,正如您将看到的那样。接下来,“标准”IContainer 由 autofac 的buider.Build() 创建。此过程的下一步是创建MultitenantContainer,它采用ITenantIdentitifcationStrategy 的实例。这意味着 MultitenantContainer 及其强制依赖 - ITenantIdentitifcationStrategy - 将是单例,无论 ITenantIdentitifcationStrategy 如何在容器中注册。在您的情况下,它会从该标准的“根”容器中解析以管理其依赖项 - 好吧,这就是 autofac 无论如何。一般来说,这种方法一切都很好,但这是你的问题真正开始的地方。当 autofac 解析此实例时,它会完全按照预期执行 - 将所有依赖项注入到 TenantIdentitifcationStrategy 的构造函数中,包括 IHttpContextAccessor。因此,在构造函数中,您从该上下文访问器中获取 IHttpContext 的实例并将其存储以用于租户解析过程 - 这是一个致命的错误:此时没有 http 请求,并且由于 @ 987654334@ 是一个单例,这意味着它永远不会有一个! 因此,它会在整个应用程序生命周期内获取null 请求上下文。这实际上意味着TenantIdentitifcationStrategy 将无法根据 http 请求解析租户标识符——因为它实际上并没有分析它们。因此,MultitenantContainer 将无法解析任何特定于租户的服务。

现在问题明确了,它的解决方案就显而易见了——只需将请求上下文context = _httpContextAccessor.HttpContext 的获取移至TryIdentifyTenant() 方法即可。它在适当的上下文中被调用,并且能够访问请求上下文并对其进行分析。

PS。由于我完全不了解 autofac 的多租户概念,所以这次挖掘对我来说很有教育意义,所以非常感谢你提出这样一个有趣的问题! :)

PPS。还有一件事:这个问题只是一个完美的例子,说明了精心准备的例子是多么重要。你提供了很好的例子。没有它,没有人能够弄清楚问题出在哪里,因为问题中没有提出最重要的部分 - 有时你只是不知道这部分实际上在哪里......

【讨论】:

  • 好发现!是的,我应该尝试预先做一个完整的回购,但希望有一些简单的东西我从文档中遗漏了,因为我花了一段时间将所有内容提取到最低限度。所以超级有趣的后续,如果你尝试在完整的 IIS 而不是 IIS Express 中运行完全相同的代码,autofac 会给出相同的错误,即无法找到 BaseContext。我刚刚开始挖掘并试图找出原因,但如果你有任何想法@AlexanderLeonov 让我知道
  • @Dan - 我们从未尝试在 iis 上托管我们的 .net 核心项目,我们使用 kestrel 和前面的 apache 在 linux 上托管它,所以,我很可能无法来帮助你。此外,我们团队中没有人喜欢 IIS。 :) 但我希望有类似的东西 - 只是一些微小的小细节或设置,它们甚至与你的多租户事情无关,但仍然搞砸了一切。 :)
猜你喜欢
  • 1970-01-01
  • 2015-03-20
  • 1970-01-01
  • 2021-03-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-10
  • 1970-01-01
相关资源
最近更新 更多