Hangfire - 多租户,ASP.NET Core - 解析正确的租户 [英] Hangfire - Multi tenant, ASP.NET Core - Resolving the correct tenant

查看:28
本文介绍了Hangfire - 多租户,ASP.NET Core - 解析正确的租户的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I got a SaaS project that needs the use Hangfire. We already implemented the requirements to identify a tenant.

架构

  • 持久层
    • 每个租户都有自己的数据库
    • 我们已经有一个服务 TenantCurrentService,它从源列表中返回租户的 ID [主机名、查询字符串等]
    • 我们已经有一个用于实体框架的 DbContextFactory,它为客户端返回一个带有正确连接字符串的数据库上下文
    • 我们目前正在使用 ASP.NET Core DI(如果有帮助,我们愿意进行更改)
    • We already have a service TenantCurrentService which returns the ID of the tenant, from a list of source [hostname, query string, etc]
    • We already have a DbContextFactory for Entity Framework which return a DB context with the correct connection string for the client
    • We are currently using ASP.NET Core DI (willing to change if that helps)
    • 使用单一存储(例如:Postgresql),无论租户数量如何
    • 在适当的 Container/ServiceCollection 中执行作业,以便我们检索正确的数据库、正确的设置等.

    问题

    我正在尝试将 TenantId 标记到作业,从 TenantCurrentService(这是一个范围服务)检索.

    I'm trying to stamp a TenantId to a job, retrieved from TenantCurrentService (which is a Scoped service).

    当作业被执行时,我们需要从作业中检索 TenantId 并将其存储在 HangfireContext 中,然后 TenantCurrentService知道从 Hangfire 检索到的 TenantId.从那里,我们的应用层将能够从我们的 DbContextFactory

    When the job then gets executed, we need to retrieve the TenantId from the Job and store it in HangfireContext, so then the TenantCurrentService knows the TenantId retrieved from Hangfire. And from there, our application layer will be able to connect to the right database from our DbContextFactory

    当前状态

    • 目前,我们已经能够使用 IClientFilter 存储从我们的服务中检索到的tenantId.
    • 如何从 IServerFilter(负责检索保存的作业参数)检索我当前的 ASP.NET Core DI ServiceScope,以便我可以调用 .GetRequiredService().IdentifyTenant(tenantId)
    • Currently, we have been able to store tenantId retrieved from our Service using a IClientFilter.
    • How can I retrieve my current ASP.NET Core DI ServiceScope from IServerFilter (which is responsible to retrieve the saved Job Parameters), so I can call .GetRequiredService().IdentifyTenant(tenantId)

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

    Is there any good article regarding this matter / or any tips that you guys can provide?

    推荐答案

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

    First, you need to be able to set the TenantId in your TenantCurrentService. Then, you can rely on filters :

    客户端(您将作业排入队列的地方)

    client side (where you enqueue jobs)

    public class ClientTenantFilter : IClientFilter
    {
            public void OnCreating(CreatingContext filterContext)
            {
               if (filterContext == null) throw new ArgumentNullException(nameof(filterContext));
    
                filterContext.SetJobParameter("TenantId", TenantCurrentService.TenantId);
            }
    }
    

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

    and server side (where the job is dequeued).

    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 配置服务器时,可以声明服务器过滤器:

    The server filter can be declared when you configure your server through an IJobFilterProvider:

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

    ServerFilterProvider 在哪里:

    where ServerFilterProvider is :

    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 时声明客户端过滤器

    The client filter can be declared when you instantiate a BackgroundJobClient

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

    其中 ClientFilterProvider 表现为 ServerFilterProvider,提供客户端过滤器

    where ClientFilterProvider behaves as ServerFilterProvider, delivering client filter

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

    A difficulty may be to have the TenantCurrentService available in the filters. I guess this should be achievable by injecting factories in the FilterProviders and chain it to the filters.

    我希望这会有所帮助.

    这篇关于Hangfire - 多租户,ASP.NET Core - 解析正确的租户的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆