aspnet core 应用程序中的 Autofac.Multitenant 似乎无法正确解析租户范围的依赖项

2023-11-29

我正在升级利用 Autofac.Multitenant 框架的多租户 dotnet 核心解决方案。我没有太多运气让租赁解决方案正常工作。我在这里创建了一个简单的问题演示:https://github.com/SaltyDH/AutofacMultitenancy1

该存储库演示了注册InstancePerTenant范围依赖TestMultitenancyContext这在家庭控制器中解决。由于使用 IHttpContextAccessor 的问题,我正在使用自定义RequestMiddleware类来捕获当前的 HttpContext 对象,以便我可以对当前 HttpContext 请求对象执行逻辑MultitenantIdentificationStrategy.

最后,TestFixture提供了一个简单的 xUnit 测试,至少在我的机器上为两个租户返回“tenant1”。

我在这里错过了什么或者这只是目前不起作用?


更新 10/6/2017: 我们发布了 Autofac.AspNetCore.Multitenant将解决方案封装在一个更易于使用的包中。我将把最初的答案/解释留在这里供后代使用,但如果你遇到了这个问题,你可以去拿那个包裹并继续前进。


我认为你遇到了时间问题。

如果您在中间件中的 HttpContext 上弹出打开调试器,您可以看到有一个RequestServicesFeature属性上的对象称为ServiceProvidersFeature. 这就是负责创建每个请求范围的内容。作用域是在第一次访问时创建的。

看起来顺序大致是这样的:

  1. The WebHostBuilder添加启动过滤器以允许将请求服务添加到管道中.
  2. 启动过滤器,AutoRequestServicesStartupFilter,将中间件添加到管道的最开始,以触发请求服务的创建。
  3. 添加的中间件,RequestServicesContainerMiddleware,基本上只是调用RequestServices财产来自ServiceProvidersFeature触发每个请求生命周期范围的创建。然而,在它的构造函数中是它得到的地方IServiceScopeFactory它用来创建请求范围,这不是很好,因为它将从根容器创建在建立租户之前.

所有这些都会产生一种情况,即每个请求的范围已被确定为默认租户,并且您无法真正更改它。

要解决此问题,您需要自行设置请求服务,以便它们考虑多租户。

听起来比实际情况更糟。

首先,我们需要对应用程序容器的引用。我们需要能够从应用程序级服务而不是请求服务来解决某些问题。我通过添加一个来做到这一点static财产给你的Startup类并将容器保留在那里。

public static IContainer ApplicationContainer { get; private set; }

接下来,我们将更改您的中间件,使其看起来更像RequestServicesContainerMiddleware.您需要设置HttpContext首先,让您的租户 ID 策略发挥作用。之后,您可以获得IServiceScopeFactory并遵循与他们相同的模式RequestServicesContainerMiddleware.

public class RequestMiddleware
{
  private static readonly AsyncLocal<HttpContext> _context = new AsyncLocal<HttpContext>();

  private readonly RequestDelegate _next;

  public RequestMiddleware(RequestDelegate next)
  {
    this._next = next;
  }

  public static HttpContext Context => _context.Value;

  public async Task Invoke(HttpContext context)
  {
    _context.Value = context;
    var existingFeature = context.Features.Get<IServiceProvidersFeature>();
    using (var feature = new RequestServicesFeature(Startup.ApplicationContainer.Resolve<IServiceScopeFactory>()))
    {
      try
      {
        context.Features.Set<IServiceProvidersFeature>(feature);
        await this._next.Invoke(context);
      }
      finally
      {
        context.Features.Set(existingFeature);
        _context.Value = null;
      }
    }
  }
}

现在您需要一个启动过滤器来将中间件放入其中。您需要一个启动过滤器,否则RequestServicesContainerMiddleware将在管道中运行得太早,并且事情已经从错误的租户范围开始解决。

public class RequestStartupFilter : IStartupFilter
{
  public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next)
  {
    return builder =>
    {
      builder.UseMiddleware<RequestMiddleware>();
      next(builder);
    };
  }
}

将启动过滤器添加到服务集合的最开始处。您需要先运行启动过滤器AutoRequestServicesStartupFilter.

The ConfigureServices最终看起来像这样:

public IServiceProvider ConfigureServices(IServiceCollection services)
{
  services.Insert(0, new ServiceDescriptor(typeof(IStartupFilter), typeof(RequestStartupFilter), ServiceLifetime.Transient));
  services.AddMvc();

  var builder = new ContainerBuilder();
  builder.RegisterType<TestMultitenancyContext>().InstancePerTenant();

  builder.Populate(services);
  var container = new MultitenantContainer(new MultitenantIdentificationStrategy(), builder.Build());
  ApplicationContainer = container;
  return new AutofacServiceProvider(container);
}

请注意Insert在那里调用以将您的服务注册堵塞在顶部,在其启动过滤器之前。

新的操作顺序将是:

  1. At app startup...
    1. 您的启动过滤器会将您的自定义请求服务中间件添加到管道中。
    2. The AutoRequestServicesStartupFilter将添加RequestServicesContainerMiddleware到管道。
  2. During a request...
    1. 您的自定义请求中间件将根据入站请求信息设置请求服务。
    2. The RequestServicesContainerMiddleware将看到请求服务已经设置并且不会执行任何操作。
    3. 解析服务后,请求服务范围将已经是自定义请求中间件设置的租户范围,并且将显示正确的内容。

我通过将租户 ID 切换为来自查询字符串而不是主机名(因此我不必设置主机文件条目和所有这些爵士乐)在本地进行了测试,并且我能够通过切换查询字符串参数来切换租户。

现在,您也许可以稍微简化一下。例如,您可以通过直接对 Web 主机构建器执行某些操作来摆脱启动过滤器Program班级。您也许可以直接使用以下命令注册您的启动过滤器ContainerBuilder打电话之前builder.Populate并跳过那个Insert称呼。您也许可以存储IServiceProvider in the Startup类属性(如果您不喜欢 Autofac 在系统中传播)。如果您自己创建中间件实例并将容器作为构造函数参数传入,那么您可能无需静态容器属性即可摆脱困境。不幸的是,我已经花了很多时间试图找出解决方法,所以我不得不把“优化它”作为读者的练习。

再次抱歉,这并不清楚。我已经代表您提出了一个问题,以更新文档,并可能找到一种更简单的更好方法来做到这一点。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

aspnet core 应用程序中的 Autofac.Multitenant 似乎无法正确解析租户范围的依赖项 的相关文章

随机推荐

  • 在shopify中编写自定义搜索应用程序

    我需要在 Shopify 中实现我们自己的自定义产品搜索 但我一直无法找到具体的操作方法 我不是在谈论显示搜索结果的模板 而是我们需要编写自定义代码来准确决定哪些产品应显示在搜索页面上及其顺序 我可以看到有很多应用程序提供自定义搜索结果 顺
  • 更新 .NET Core 工具

    我正在尝试使用 电子邮件受保护 为了在这一点上做到这一点 我已经有了 安装了 Visual Studio 2019 预览版 安装了 NET Core 3 1运行时 安装了 NET Core 3 1 SDK 现在我仍然无法运行命令dotnet
  • R[写入控制台]:gettext(fmt,domain = domain,trim = trim)中的错误:3个参数传递给.Internal(gettext),需要2个

    我想在python中使用R函数 我在python中安装了rpy2 当我想加载函数 from rpy2 import robjects 时 我面临以下错误 R 写入控制台 gettext fmt domain domain trim trim
  • MapOverlay 绑定不起作用

    我正在尝试使用 MVVM 代码结构在 Windows Phone 8 上运行地图叠加 我似乎无法将 MapOverlay 的 GeoCoordinate 属性正确绑定到我的 ViewModel 而且我不知道为什么 目前的 XAML 是 He
  • 在jqGrid中,是否可以使用Ajax来获取custom_element的数据?

    我正在做某事类似于这个问题我有一个复选框列表作为自定义编辑控件 不同之处在于我想从服务器获取我的列表 而不是在客户端上硬编码 检查1 检查2 检查3 有什么方法可以在列设置或在自定义元素功能 看来我需要类似的东西dataUrl您用于选择项目
  • 从多个表中获取数据

    医学硕士 MedicalID MedicalName 1 pk abc 2 xyx 3 pqr 儿童医学硕士 ChildMID MedicalID Station Name 1 pk 1 fk bnb mfk 2 1 def rwr 3 2
  • 使用 LINQ 获取多维数组的分区(N 维数组的 (N-1) 维实例)

    我想从 3d 数组中获取 2d 数组 假设我有一个维度为 10 10 10 的双 3d 数组 A3我需要获得一个二维数组 A2 A3 5 即第二维的索引等于例如5 如果我想获得 2d 数组 A2 即 2d 数组的 1d 实例 的分区 例如
  • 查找嵌套在 Repeater 控件内的控件

    我正在尝试查找在中继器中呈现的文本框的值thoughUserControl 即 Repeater 有一个 UserControl 的占位符 UserControl 内部是 TextBox 标记实际存在的位置 我以前用文本框做过这个直接在里面
  • 如何在 JavaScript 中使用 fetch() 读取 JSON 文件?

    如何使用 javascript 中的 fetch 函数读取本地 JSON 文件 我有一个包含一些转储数据的 JSON 文件和一个读取服务器上 JSON 文件的函数 例如 readJson console log this let vm th
  • 如何将数字附加到 XSL 文件内的 ID

    我有以下 XSL 文件 该文件将重复多次 在我的例子中为 4 次
  • 如何从另一个线程更新 GUI?

    我的线程有问题JSF申请 也许有人可以帮助我 启动后 我运行新线程 该线程正在进行一些后台操作 该线程正在工作while true loop 但当它无能为力时 它会调用wait 它正在循环工作 因为我必须调用notify 在一些用户操作之后
  • BeanUtils 复制属性:注册 ConvertUtils

    我有用 Java 编写的 Web 应用程序 我在用着BeanUtils copyProperties方法 如果一个date字段为空 会抛出错误 我通过使用解决了它ConvertUtils register method ConvertUti
  • Spring Data Neo4j:使用嵌入的 Neo4j 服务器:JAR 打包

    我终于能够在我的 java 应用程序中创建一个使用嵌入式数据库的服务器实例 如下所示here 当我从 Eclipse 运行它时 它可以正常工作 但这实际上不是我的目的 除其他事项外 我的应用程序向数据库提供新的节点和关系 我有一个 Neo4
  • OWL 2 罗化

    在描述逻辑中 有一个概念叫 rolification OWL 和规则 第 3 2 节 它将概念 类 转换为角色 属性 例如 当我们滚动时R x 我们得到r x x 该技术对于在深度学习中表达一些规则很有用 我们如何在 OWL 2 中做到这一
  • 使用 Mule 发送格式化邮件

    我正在使用 Mule 发送电子邮件 我需要为发送的文本添加格式 邮件的内容是有效负载 其中包含我在 Java 方法中形成的字符串 并使用表达式转换器发送到流程 我需要向该字符串添加格式 粗体 下划线 颜色 我该怎么做 这是我的流程的摘录
  • 如何使用 PHP GD 显示动态生成的内嵌图像

    我正在尝试使用 PHP GD 合并图像来动态生成图像 我想知道是否有一种方法可以在我的网页中显示图像 而不需要将其存储在服务器上的某个位置 例如 我创建了以下代码来合并图像 function create image main image
  • 乘客安装时出现转换错误。对 nginx 模块有影响吗?

    在OS X 10 6 8下安装passenger 首先在rbenv下 然后卸载rbenv后 也在rvm下 Mini user gem install passenger 正在生成转换错误 unable to convert xE4 to U
  • Pygame 需要“for event in pygame.event.get()”以免崩溃

    该程序像这样工作正常 但是 我不明白为什么它需要无用的for event in pygame event get None in the gameOverwhile 语句里面game loop 如果您能找到一种方法来删除它或解释为什么没有它
  • 使用内置 Python 模块填写 Web 表单数据

    好吧 我已经在我的冒险中使用了 mechanize requests beautiful soup 甚至 selenium 来做这样的事情 我得出的结论是 urllib 和其他默认模块是最好的方法 唯一的问题是我根本不知道如何使用它 那么有
  • aspnet core 应用程序中的 Autofac.Multitenant 似乎无法正确解析租户范围的依赖项

    我正在升级利用 Autofac Multitenant 框架的多租户 dotnet 核心解决方案 我没有太多运气让租赁解决方案正常工作 我在这里创建了一个简单的问题演示 https github com SaltyDH AutofacMul