2013-01-21 26 views
2

我们使用NServiceBus和Ninject来实现多租户SaaS应用程序。NServiceBus和Ninject - 访问NSB消息属性

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

在我们的NSB Windows服务,我们没有一个共享的情况下,使我们能够确定主机数据库连接的那个概念,所以我们创建存放帐户/数据库对我们的基本命令类的属性谁创建了命令/消息。

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

正如之前所说,Ninject能够访问正确的数据库中的HttpContext Web请求,但为NSB服务本身包含我们只能在处理后接入构造,这显然失败了DB细节的消息,因为它需要一个参数(包含在消息中!)成功构建存储库。鸡和蛋:)

这是问的长篇大论方式...

  • 反正是有在Ninject创建周期内访问消息的属性?
  • 这感觉就像是那些难以解决的难题之一,因为我的架构“错误”,是这样吗?
  • 我想避免在“SetDatabase”这样的资源库上放置公共属性,因为这样可能会很容易被滥用/误解并导致用户数据混乱。
  • 我也想过创建一个存储库工厂,Ninject会使用但仍不知道如何访问传入消息属性。

在此先感谢!


编辑为解决

我结束了使用从乌迪和埃本答案的混合方法。

我对我的API消息使用了出去消息增发器,它将客户的账户名添加到出站消息的头文件(来自HttpContext)。 然后,在NSB Windows服务中,我使用一个入站增强器来检查标题并提取帐户名称,如Udi所示。

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

我不能标记既是正确的,对不起埃本!:)

+0

我有一个类似的架构,以及类似的问题。你是如何配置你的容器注册以从入站消息变更器中获取租户的?你能分享一些代码吗? – Junto

回答

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

我也建议使用您的邮件标头之类的信息,而不是把它放在一个基类。

+0

感谢乌迪,是因为帐户信息的标题建议。是关于连接的元数据? –

+0

会一个传送消息的Mutator是适合于正确的帐户名称添加到出站消息和工作单元开始()被用于检查入站消息头的方法? –

0

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

要变通解决此问题,可能需要一个ITenantProvider,它由HttpTenantProviderThreadStaticTenantProvider执行。为你的网站,你可以注入HTTP版本到存储库,它会问,比如说,TenantProvider.DatabaseName实例(或任何你需要的)。对于端点实现,您可以使用'线程静态'实现。我只是说线程静态,因为您将要从多个线程访问租户提供程序实例,并且可能需要线程特定的状态。但是,你决定这样做取决于你:)

在你的消息处理开始时,你可以投射到线程静态版本,并沿着((TheadStaticTenantProvider)TenantProvider).SetCurrentMessage(theMessage)行调用某些东西。然后,存储库将通过消息的线程静态租户提供程序接收所需的数据。

Shuttle我们使用处理管道,所以我会创建一个模块插入到处理接收到的消息的管道中,以便为我在租户提供商上设置消息。我不知道NServiceBus不够好,但有可能是类似的东西在那里收到消息后,设置此为你,你可以挂接到一个事件。

我希望我是有道理的:)

+0

谢谢,我实际使用这样的一个模型连接字符串,我不知道为什么我没有想到来扩展... :) 为了澄清,你的建议是,每一个消息处理程序将不得不调用方法,设置当前消息能够访问主机名?大概在一个基类或一些这样的? –