【问题标题】:Hangfire - Multi tenant, ASP.NET Core - Resolving the correct tenantHangfire - 多租户,ASP.NET Core - 解析正确的租户
【发布时间】:2019-12-15 02:37:19
【问题描述】:

我有一个需要使用 Hangfire 的 SaaS 项目。我们已经实施了识别租户的要求。

架构

  • 持久层
    • 每个租户都有自己的数据库
  • .NET 核心
    • 我们已经有一个服务TenantCurrentService,它从源列表[主机名、查询字符串等]中返回租户的ID
    • 我们已经有一个用于 Entity Framework 的 DbContextFactory,它返回一个带有正确连接字符串的数据库上下文,用于客户端
    • 我们目前正在使用 ASP.NET Core DI(如果有帮助,愿意更改)
  • 吊火
    • 无论租户数量如何,都使用单一存储(例如:Postgresql)
    • 在适当的 Container/ServiceCollection 中执行作业,以便我们检索正确的数据库、正确的设置等。

问题

我正在尝试将 TenantId 标记为从 TenantCurrentService 检索到的作业(这是一个 Scoped 服务)。

当作业随后执行时,我们需要从作业中检索TenantId 并将其存储在HangfireContext 中,这样TenantCurrentService 就知道从Hangfire 检索到的TenantId。从那里,我们的应用层将能够从我们的DbContextFactory 连接到正确的数据库

当前状态

  • 目前,我们已经能够使用IClientFilter 存储从我们的服务中检索到的tenantId。
  • 如何从 IServerFilter(负责检索保存的作业参数)中检索当前的 ASP.NET Core DI ServiceScope,以便调用 .GetRequiredService().IdentifyTenant(tenantId)

有没有关于这个问题的好文章/或者你们可以提供任何提示?

【问题讨论】:

  • 听起来你已经用 Hangfire 和 ASP.NET 核心 DI 解决了很多问题。你能指出任何描述复杂位的文章吗?目前,我在适当的 Container/ServiceCollection 中执行作业时遇到问题,因此在处理作业时与处理 Web 请求时它获得的依赖关系不同。 stackoverflow.com/questions/66618098/…

标签: c# asp.net-core dependency-injection .net-core hangfire


【解决方案1】:

首先,您需要能够在您的TenantCurrentService 中设置TenantId。 然后,您可以依赖过滤器:

客户端(将作业排入队列的位置)

public class ClientTenantFilter : IClientFilter
{
        public void OnCreating(CreatingContext filterContext)
        {
           if (filterContext == null) throw new ArgumentNullException(nameof(filterContext));

            filterContext.SetJobParameter("TenantId", TenantCurrentService.TenantId);
        }
}

和服务器端(作业出队的地方)。

public class ServerTenantFilter : IServerFilter
{
    public void OnPerforming(PerformingContext filterContext)
    {
      if (filterContext == null) throw new ArgumentNullException(nameof(filterContext));

      var tenantId = filterContext.GetJobParameter<string>("TenantId");
      TenantCurrentService.TenantId = tenantId;
    }
}

可以在通过IJobFilterProvider 配置服务器时声明服务器过滤器:

        var options = new BackgroundJobServerOptions
        {
            Queues = ...,
            FilterProvider = new ServerFilterProvider()
        };
        app.UseHangfireServer(storage, options, ...);

ServerFilterProvider 在哪里:

public class ServerFilterProvider : IJobFilterProvider
{
    public IEnumerable<JobFilter> GetFilters(Job job)
    {
        return new JobFilter[]
                   {
                       new JobFilter(new CaptureCultureAttribute(), JobFilterScope.Global, null),
                       new JobFilter(new ServerTenantFilter (), JobFilterScope.Global,  null),
                   };
    }
}

可以在实例化 BackgroundJobClient 时声明客户端过滤器

var client = new BackgroundJobClient(storage, new BackgroundJobFactory(new ClientFilterProvider());

其中ClientFilterProvider 的行为类似于ServerFilterProvider,提供客户端过滤器

一个困难可能是让 TenantCurrentService 在过滤器中可用。我想这应该可以通过在 FilterProviders 中注入工厂并将其链接到过滤器来实现。

我希望这会有所帮助。

【讨论】:

  • 感谢您的精彩回答!我现在可以使用IClientFilter 在作业参数中标记 TenantId。如何从IServerFilter(负责检索保存的作业参数)中检索我当前的ASP.NET Core DI ServiceScope,以便我可以调用.GetRequiredService&lt;ITenantCurrentService&gt;().IdentifyTenant(tenantId)
  • @Dekim 我不知道。我不将 HF 与 Aspnet Core 一起使用。也许您应该在 FilterProvider 中包含 ServiceScope 或工厂,然后可以将其提供给过滤器
  • @dekim 你搞清楚这个了吗?
猜你喜欢
  • 1970-01-01
  • 2018-08-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-30
  • 2012-09-24
相关资源
最近更新 更多