Search code examples
dependency-injectioncastle-windsornservicebus

NServiceBus handler set named dependency with Castle Windsor


For an NServiceBus handler I want to specify a named dependency. I am using castle windsor as my IOC container. By default NServiceBus registers all handlers with the container so when I try to also set registrations it throws an error on startup.....

"Component EventMessageHandler could not be registered. There is already a component with that name. Did you want to modify the existing component instead? If not, make sure you specify a unique name.".

Is there a way to override this to specify the named dependency. So have a registration like this...

container.Register(
Component.For<IService>()
    .ImplementedBy<Service>()
    .Named("default")
    .DependsOn(Dependency.OnValue<Config>(config1)));

container.Register(
Component.For<IHandleMessages<EventMessage>>().ImplementedBy<EventMessageHandler>()
    .DependsOn(Dependency.OnComponent(typeof(IService), "default")));

For a handler that looks like this....

public class EventMessageHandler : IHandleMessages<EventMessage>
{
    private IService service;

public EventMessageHandler(IService service)
{
    this.service = service;
}

public void Handle(EventMessage message)
{
    service.DoStuff();
}
}

This is because I have multiple implementations of the IService so want to be able to specify specific ones for specific handlers.


Solution

  • It is possible to do it by creating a container, preregister everything and then hand it over to the BusConfiguration (assuming you're on NSB v5.0 or greater).

    Here's the code:

    BusConfiguration busConfiguration = new BusConfiguration();
    WindsorContainer container = new WindsorContainer();
    
    container.Register(Component.For<IMyService>().ImplementedBy<MyServiceImpl1>().Named("s1"));
    container.Register(Component.For<IMyService>().ImplementedBy<MyServiceImpl2>().Named("s2"));
    container.Register(Component.For<MyMessageHandler>().DependsOn(Dependency.OnComponent(typeof(IMyService), "s1")));
    
    busConfiguration.UseContainer<WindsorBuilder>(c => c.ExistingContainer(container));
    

    Now on your handler, if you have a dependency to your service, it will be the one you've specified:

    public class MyMessageHandler : IHandleMessages<MyMessage>
    {
        public MyMessageHandler(IMyService service)
        {
           //service is of the type you specified in your config
        }
    
        public void Handle(MyMessage message)
        {
            Console.WriteLine("Message arrived");
        }
    }
    

    One thing to note, you'd have to do your registration exactly as shown above. If you try to do it this way it will blow up:

    //Wouldn't work
    container.Register(Component.For<IHandleMessages<MyMessage>>().ImplementedBy<MyMessageHandler>().DependsOn(Dependency.OnComponent(typeof(IMyService), "s2")));
    

    Having said all that, why is it bad to inject the actual class and not the interface to achieve the same thing?