我有一个多租户应用程序,它使用作用域依赖项从传入的 httprequests 中检索 tenantId 到 Azure 函数,并根据租户实例化各种资源。 例如:
services.RegisterScoped((sp)=>
{
var httpContextAccessor = sp.GetRequiredService<IHttpContextAccessor>();
var tenantId = httpContextAccessor.GetTenantId(); // extension method
// Instantiate some other tenant specific dependencies e.g. DBContext.
});
现在,我有一个 ServiceBusTrigger 可以处理所有租户的消息。 ServiceBusReceivedMessage 参数包含一个具有 tenantId 属性的对象,以便每条消息都可以针对特定租户进行处理。
有没有办法让 ServiceBusReceivedMessage 从函数中实例化资源,比如 DbContext?这是必要的,因为每个消息可能必须通过 DbContext 持久化一些数据,需要根据消息中的 tenantId 使用特定的连接字符串实例化。
我考虑过的一些事情:
使用Activator.CreateInstance(//手动获取后传入租户连接字符串)
ServiceBusRecievedMessage 是否可以在每条消息的 serviceBusTrigger 中注册?这看起来很老套(没有直接的方法来做到这一点),但也是最受欢迎的方法,因为可以利用其余的 DI 容器,而不必像第一个选项那样手动实例化对象。
[FunctionName("MyCustomTrigger")]
public Task Run(
[ServiceBusTrigger("MultiTenantEndpoint")]
ServiceBusReceivedMessage message,
ServiceBusClient client,
ServiceBusMessageActions messageActions,
ILogger logger,
ExecutionContext executionContext)
{
var tenantId = message.GetTenantId(); // 仅以某种方式将 tenantId 注册为该请求的范围? await injectedService.Process(消息); }
替代方法或设计?
简短回答:不可能执行上述操作,因为 serviceBusTrigger 的范围不限于任何类型的请求,因此 DI 仅在启动时起作用。
我们最终将 tenantId 嵌入到 serviceBusMessage 中,然后在收到 SB 消息时向同一服务上的端点发送 HTTP 请求,这确保了正确的资源被 DI 到消费服务层。