Search code examples
asp.netasp.net-web-apidependency-injectionunity-containerasp.net-apicontroller

Resolve names registration from Unity which creating a controller


I am working on an ASP.NET Web API which contains multiple Web API Controllers. Each controller has a dependency on IMessageSender.

public class OrderController: ApiController {
    private readonly IMessageSender _msgSender;
    public OrderController(IMessageSender msgSender) {
        _msgSender = msSender;
    }
}

I have 3 different different implementations of IMessageSender - CloudMessageSender, InMemoryMessageSender and NServiceBusMessageSender.

public class CloudMessageSender: IMessageSender 
{
}
public class InMemoryMessageSender: IMessageSender 
{
}
public class NServiceBusMessageSender: IMessageSender 
{
}

I am using Unity and Unity.WebApi for dependency resolution and have registered 3 named registrations of IMessageSender

container.RegisterType<IMessageSender, CloudMessageSender>("res-cloud");
container.RegisterType<IMessageSender, InMemoryMessageSender>("res-inmem");
container.RegisterType<IMessageSender, NServiceBusMessageSender>("res-nsvc");

The problem that I am facing is that for different controllers I need to use a different Implementation of IMessageSender. Ex. OrdersController need to use the CloudMessageSender but CustomersController need to use the InMemoryMessageSender. By default Unity will inject either the un-named resolution or (in my case) the first one.

How can I specify or control as to which controller should be injected with which implementation of IMessageSender?


Solution

  • You can configured the container to register for Controller type too with injection members. In the list of injection members you can resolve the already registered dependencies by the name. This way it will be made sure that the proper type gets resolved when the controller instance is created.

    container.RegisterType<IMessageSender, CloudMessageSender>("res-cloud");
    container.RegisterType<IMessageSender, InMemoryMessageSender>("res-inmem");
    container.RegisterType<IMessageSender, NServiceBusMessageSender>("res-nsvc");
    
    var messageSender = new ResolvedParameter<IMessageService>("res-cloud");
    container.RegisterType<OrderController>(new InjectionConstructor(messageSender));
    

    Now when OrderController instance is initialized, type of msgSender argument will be resolved to CloudMessageSender.

    One issue with this way of registering controller is that you need to resolve and pass all the parameters of constructor of the controller.

    Unity does not support resolving types based on name without using this approach.