根据内容重新分配多个队列

Lor*_*nzo 3 asp.net-mvc simple-injector rebus azure-servicebus-queues

设置:在 asp.net mvc 项目中使用 SimpleInjector 进行 Rebus。

我需要创建两个接收消息的处理程序,每个处理程序来自一个特定的队列。按照我在这个SO 答案中找到的内容,我创建了类似的代码。

在一个类库中,我有一个实现 SimpleInjector 的类,IPackage它的代码如下:

public void RegisterServices( Container container ) {
    container.Register<IHandleMessages<MyMessage>, MyMessageHandler>( Lifestyle.Scoped );
    IContainerAdapter adapter = new SimpleInjectorContainerAdapter( container );
    Configure.With( adapter )
             .Transport( t => t.UseAzureServiceBus( connectionString, "A_QUEUE_NAME", AzureServiceBusMode.Standard ) )
             .Options( oc => {
                 oc.SetNumberOfWorkers( 1 );
                 oc.SimpleRetryStrategy( errorQueueAddress: "A_ERROR_QUEUE_NAME", maxDeliveryAttempts: 3 );
             } )
             .Start();

    Configure.With(adapter
             .Transport(t => t.UseAzureServiceBus(connectionString, "B_QUEUE_NAME")
             .Options( oc => {
                 oc.SetNumberOfWorkers( 1 );
                 oc.SimpleRetryStrategy( errorQueueAddress: "B_ERROR_QUEUE_NAME", maxDeliveryAttempts: 3 );
             } )
             .Start();
}
Run Code Online (Sandbox Code Playgroud)

但是,当调试器进入第二个 Configure.With( ... ) 调用时,我以错误提示终止:

IBus 类型已经注册。如果您打算解析 IBus 实现的集合,请使用 RegisterCollection 重载。更多信息:https : //simpleinjector.org/coll1。如果您打算用此新注册替换现有注册,您可以通过将 Container.Options.AllowOverridingRegistrations 设置为 true 来允许覆盖当前注册。更多信息:https : //simpleinjector.org/ovrrd

堆栈跟踪:

[InvalidOperationException: Type IBus has already been registered. If your intention is to resolve a collection of IBus implementations, use the RegisterCollection overloads. More info: https://simpleinjector.org/coll1. If your intention is to replace the existing registration with this new registration, you can allow overriding the current registration by setting Container.Options.AllowOverridingRegistrations to true. More info: https://simpleinjector.org/ovrrd.]
   SimpleInjector.Internals.NonGenericRegistrationEntry.ThrowWhenTypeAlreadyRegistered(InstanceProducer producer) +102
   SimpleInjector.Internals.NonGenericRegistrationEntry.Add(InstanceProducer producer) +59
   SimpleInjector.Container.AddInstanceProducer(InstanceProducer producer) +105
   SimpleInjector.Container.AddRegistrationInternal(Type serviceType, Registration registration) +69
   SimpleInjector.Container.AddRegistration(Type serviceType, Registration registration) +131
   SimpleInjector.Container.RegisterSingleton(TService instance) +183
   Rebus.SimpleInjector.SimpleInjectorContainerAdapter.SetBus(IBus bus) +55
   Rebus.Config.RebusConfigurer.Start() +2356
   MyModule.RegisterServices(Container container) +497
   SimpleInjector.PackageExtensions.RegisterPackages(Container container, IEnumerable`1 assemblies) +50
   Myproject.SimpleInjectorInitializer.InitializeContainer(Container container) +35
   Myproject.SimpleInjectorInitializer.Initialize() +68
   Myproject.Startup.Configuration(IAppBuilder app) +28
Run Code Online (Sandbox Code Playgroud)

编辑

然后我删除了第二个Configure.With( ... )代码块,现在当我做一个时,我_bus.Send( message )在消费者进程中遇到另一个错误,它说

处理 ID 为 fef3acca-97f4-4495-b09d-96e6c9f66c4d 的消息时未处理的异常 1:SimpleInjector.ActivationException:找不到 IEnumerable<IHandleMessages<MyMessage>> 类型的注册。然而,有一个 IHandleMessages<MyMessage> 的注册;你是想调用 GetInstance<IHandleMessages<MyMessage>>() 还是依赖 IHandleMessages<MyMessage>?或者您的意思是使用 RegisterCollection 注册类型集合?

堆栈跟踪:

2017-04-13 10:21:03,805 [77] WARN  Rebus.Retry.ErrorTracking.InMemErrorTracker - 
   at SimpleInjector.Container.ThrowMissingInstanceProducerException(Type serviceType)
   at SimpleInjector.Container.GetInstanceForRootType[TService]()
   at SimpleInjector.Container.GetInstance[TService]()
   at SimpleInjector.Container.GetAllInstances[TService]()
   at Rebus.SimpleInjector.SimpleInjectorContainerAdapter.<GetHandlers>d__3`1.MoveNext()
Run Code Online (Sandbox Code Playgroud)

moo*_*000 5

我通常建议IBus每个容器实例只保留一个,因为总线本身可以被视为“一个应用程序”,这恰好符合 IoC 容器是一个可以在其持续时间内“托管”应用程序的对象的事实。寿命。

Rebus 没有提供 Conforming Container 抽象,因为我同意 Mark Seemann 的观点,这是一个注定要失败的项目。事实上,正如wiki 页面所提到的,Rebus 曾经提供处理程序的自动注册,但结果证明这是有问题的。

相反,Rebus 鼓励您提供一个“容器适配器”(实现IContainerAdapter),其职责是:

  • 查找处理程序
  • 提供一种注册方式IBusIMessageContext以正确的方式

其中容器适配器是为 Autofac、Castle Windsor、SimpleInjector 等提供开箱即用的。但是,不需要提供容器适配器——Configure.With(...)咆哮很高兴只收到一个“处理程序激活器”(实现IHandlerActivator),所以如果你只想要使用您的 IoC 容器来查找处理程序并自行注册IBus,您也可以通过IHandlerActivator在容器中实现和查找处理程序来做到这一点。

TL;DR:Rebus 方式是将 IoC 容器的实例视为一个单独的应用程序,因此只IBus在其中注册一个是有意义的。

在单个进程中新建多个容器实例(或什至具有不同消息 SLA 的应用程序的多个实例)的多个容器实例是完全没问题的。

  • 让我们解决这个问题 :) 我创建了 [this issue](https://github.com/simpleinjector/SimpleInjector/issues/404),我在其中询问如何使用 SimpleInjector 满足 Rebus 的要求。 (2认同)