Hangfire - 多租户,ASP.NET Core - 解析正确的租户 [英] Hangfire - Multi tenant, ASP.NET Core - Resolving the correct tenant
问题描述
我有一个需要使用 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 inHangfireContext
, so then theTenantCurrentService
knows the TenantId retrieved from Hangfire. And from there, our application layer will be able to connect to the right database from ourDbContextFactory
当前状态
- 目前,我们已经能够使用
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 yourTenantCurrentService
. 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 asServerFilterProvider
, 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屋!