2

我们将 NServiceBus 和 Ninject 用于多租户 SaaS 应用程序。

当用户访问我们的网站或 API 时,我们可以通过检查 HttpContext Request 对象的主机名、检索有关该帐户的各种设置(其中一个是我们应该连接的数据库)来确定用户连接到哪个帐户和请求的其余部分连接到正确的数据库(进行各种其他检查)。

在我们的 NSB Windows 服务中,我们没有共享上下文的概念,通过它我们可以确定要连接的主机数据库,因此我们在基本命令类上创建了一个属性,用于存储创建命令的帐户/数据库/信息。

当为传入消息构造消息处理程序时,依赖项之一是存储库,该存储库将它应该连接到的数据库的名称作为参数。

如前所述,Ninject 可以为 Web 请求访问 HttpContext 中的正确数据库,但对于 NSB 服务,消息本身包含我们只能在构造处理程序后访问的数据库详细信息,这显然会失败,因为它需要一个参数(即包含在消息中!)以成功构建存储库。鸡肉和鸡蛋:)

这是一个冗长的询问方式......

  • 在 Ninject 创建周期期间是否可以访问消息的属性?
  • 这感觉像是因为我的架构“错误”而很难解决的难题之一,是这样吗?
  • 我想避免将公共属性放在像“SetDatabase”这样的存储库上,因为感觉它很容易被滥用/误解,并对用户数据造成严重破坏。
  • 我还考虑过创建一个存储库工厂,Ninject 会使用它,但仍然不确定如何访问传入的消息属性。

提前致谢!


编辑解决方案

我最终使用了来自 Udi 和 Eben 答案的混合方法。

我为我的 API 消息使用了外出消息修改器,将客户的帐户名称添加到出站消息的标头(来自 HttpContext)。然后,按照 Udi 的建议,在 NSB Windows 服务中,我使用入站修改器来检查标头并提取帐户名称。

我还创建了两个接口实例,按照 Eben 的建议向我的存储库提供连接字符串/帐户详细信息。一种用于 Web 请求,一种 ThreadStatic 类型由传入的 mutator 设置,然后 Ninject 绑定用于 NSB 的 repo 实例化。

我不能将两者都标记为正确,抱歉 Eben!:)

4

2 回答 2

0

你肯定似乎有一点架构问题。

要解决这个问题,一个选项可能是拥有类似 a 的东西ITenantProvider,由 aHttpTenantProvider和 a实现ThreadStaticTenantProvider。对于您的网站,您可以将 http 版本注入到存储库中,它会询问实例,例如TenantProvider.DatabaseName(或任何您需要的)。对于端点实现,您可以使用“线程静态”实现。我只是说线程静态,因为您将要从多个线程访问租户提供程序实例,并且可能需要线程特定的状态。但是,无论您决定做什么,都取决于您:)

在消息处理开始时,您可以转换为线程静态版本并调用类似((TheadStaticTenantProvider)TenantProvider).SetCurrentMessage(theMessage). 然后,存储库将通过线程静态租户提供程序从消息中接收所需的数据。

Shuttle中,我们使用处理管道,因此我将创建一个模块,该模块插入到处理接收到的消息的管道中,以便为我在租户提供程序上设置消息。我不太了解 NServiceBus,但可能有类似的东西,您可以在收到消息后挂接到事件中为您设置它。

我希望我有道理:)

于 2013-01-21T12:22:57.390 回答
0

您应该考虑使用工作单元或消息修改器挂钩来完成此类工作。更多信息在这里:

http://support.nservicebus.com/customer/portal/articles/860275-unit-of-work-in-nservicebus

http://support.nservicebus.com/customer/portal/articles/860492-pipeline-management-using-message-mutators

我还建议在您的消息中使用标题来获取此类信息,而不是将其放在基类中。

于 2013-01-21T12:58:59.457 回答