将NServiceBus与ServiceStack IRequiresRequestContext集成的问题

时间:2013-05-21 13:01:58

标签: unity-container servicestack nservicebus

我希望将NServiceBus集成到现有的ServiceStack Web主机中。 ServiceStack目前正在使用内置的Funq IoC容器。 NServiceBus已经配置(在系统的其他地方)使用Unity for IoC。

当ServiceStack在类上找到IRequiresRequestContext接口时,它具有IRequestContext will be automatically injected的功能。 NServiceBus通过IMutateOutgoingTransportMessages接口为Message Mutators提供了类似的功能。

该应用程序是一个多租户应用程序。单个应用程序,通过API密钥,将帐户代码传递给NServiceBus处理程序(间接通过使用Unity构造处理程序构造函数注入时调用的提供程序)。

我的问题出现在ServiceStack中。我正在使用请求过滤器将API密钥从请求标头中拖出,我在数据库中查找,然后最终写入IHttpRequest.Items集合:

appHost.RequestFilters.Add((req, res, requestDto) =>
{
    var tenant = tenantRepository.GetByApiKey(
    req.Items.Add("AccountCode", tenant.AccountCode);
}

然后我有一个NServiceBus传输消息mutator,它实现了IRequiresRequestContext接口,这个类与AppHost中注册的ServiceStack服务位于同一个程序集中:

public class MessageHeaderMutator : IMutateOutgoingTransportMessages, INeedInitialization, IRequiresRequestContext
{
    #region IRequiresRequestContext Members

    public IRequestContext RequestContext { get; set; }

    #endregion

    #region IMutateOutgoingTransportMessages Members

    public void MutateOutgoing(object[] messages, NServiceBus.TransportMessage transportMessage)
    {
        transportMessage.Headers.Add("AccountCode", RequestContext.Get<IHttpRequest>().Items["AccountCode"].ToString());
    }

    #endregion

    #region INeedInitialization Members

    public void Init()
    {
        Configure.Instance.Configurer.ConfigureComponent<MessageHeaderMutator>(DependencyLifecycle.InstancePerCall);
    }

    #endregion
}

但是,RequestContext永远不会被注入,并始终是null。我的理论是,通过两个独立的框架注入的两个接口注入在某种程度上是冲突的。

我有一个解决方法,即根据this discussion使用ServiceStack HostContext.Items,但我担心HostContext不是每个请求集合,所以我可能会最终将数据写入错误的租户。解决方法是:

// app host
appHost.RequestFilters.Add((req, res, requestDto) =>
{
    var accountCode = tenantRepository.GetByApiKey(
    HostContext.Instance.Items.Add("AccountCode", client.AccountCode);
}


// message mutator
public class MessageHeaderMutator : IMutateOutgoingTransportMessages, INeedInitialization
{
    #region IMutateOutgoingTransportMessages Members

    public void MutateOutgoing(object[] messages, NServiceBus.TransportMessage transportMessage)
    {
        var accountCode = HostContext.Instance.Items["AccountCode"].ToString();
        transportMessage.Headers.Add("AccountCode", accountCode);
    }

    #endregion

    #region INeedInitialization Members

    public void Init()
    {
        Configure.Instance.Configurer.ConfigureComponent<MessageHeaderMutator>(DependencyLifecycle.InstancePerCall);
    }

    #endregion
}

因此我的问题有两个:

  1. 首先,为什么IRequiresRequestContext没有正确地将RequestContext注入Message mutator,或者有inject RequestContext manually方法?
  2. 使用HostContext是否安全,假设每次请求
  3. 奖金问题:在同一个项目中使用两个独立的IoC容器(NServiceBus中的Unity和ServiceStack中的Funq)是一个非常糟糕的主意吗?让ServiceStack使用与NServiceBus相同的Unity IoC容器会更聪明吗?
  4. P.S。这是NServiceBus 4(撰写本文时为测试版)。

2 个答案:

答案 0 :(得分:1)

正是因为你正在使用2个不同的容器,所以DI对于你来说不适用于在不同容器中注册的对象。

您不一定需要对单个容器进行标准化(尽管它可以帮助您免于处理这些类型的问题)。

继续使用这两个容器可以做的是告诉NServiceBus容器如何解析IRequiresRequestContext,如下所示:

public class RequestContextBootstrapper : INeedInitialization
{
   public void Init()
   {
      Configure.Component<IRequiresRequestContext>( /* get object from ServiceStack */ );
   }
}

答案 1 :(得分:1)

您可以通过AppHostBase.Container访问ServiceStack容器,并使用它来解析Udi建议的对象。