Setup: Rebus in asp.net mvc project using SimpleInjector.
I need to create two handlers which receive messages, each from a specific queue. By following what I have found on this SO answer I have created similar code.
In a class library I have a class which implements SimpleInjector IPackage
which have a code like this:
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();
}
However when the debugger get to the second Configure.With( ... ) call i terminates with an error saying:
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.
Stack trace:
[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
EDIT
I have then removed the second Configure.With( ... )
block of code and now when I do a _bus.Send( message )
I get another error in the consumer process which says
Unhandled exception 1 while handling message with ID fef3acca-97f4-4495-b09d-96e6c9f66c4d: SimpleInjector.ActivationException: No registration for type IEnumerable<IHandleMessages<MyMessage>> could be found. There is, however, a registration for IHandleMessages<MyMessage>; Did you mean to call GetInstance<IHandleMessages<MyMessage>>() or depend on IHandleMessages<MyMessage>? Or did you mean to register a collection of types using RegisterCollection?
Stack Trace:
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()
I usually recommend keeping only one single IBus
per container instance, because the bus can considered "an application" in itself, which happens to fit nicely with the fact that an IoC container is an object that can "host" an application for the duration of its lifetime.
Rebus does not provide a Conforming Container abstraction, because I agree with Mark Seemann that that is a project that is doomed to fail. In fact, as the wiki page mentions, Rebus used to provide automatic registration of handlers, but that turned out to be problematic.
Instead, Rebus encourages you to provide a "container adapter" (implementation of IContainerAdapter
) whose responsibilities are:
IBus
and IMessageContext
in The Correct Waywhere container adapters are provided out of the box for Autofac, Castle Windsor, SimpleInjector, etc. However, providing a container adapter is not required – the Configure.With(...)
rant is happy with receiving only a "handler activator" (implementation of IHandlerActivator
), so if you only want to use your IoC container to look up handlers and take care of registering IBus
yourself, you can do that too by implementing IHandlerActivator
and looking up handlers in your container.
TL;DR: The Rebus Way is to treat an instance of your IoC container as a separate application, and therefore it makes sense to register only one IBus
in it.
It is perfectly fine to new up multiple container instances of you want to host multiple applications (or even multiple instances of your application with different message SLAs) in a single process.