With Unity how do I inject a named dependency into a constructor?
Asked Answered
S

4

75

I have the IRespository registered twice (with names) in the following code:

// Setup the Client Repository
IOC.Container.RegisterType<ClientEntities>(new InjectionConstructor());
IOC.Container.RegisterType<IRepository, GenericRepository>
    ("Client", new InjectionConstructor(typeof(ClientEntities)));

// Setup the Customer Repository
IOC.Container.RegisterType<CustomerEntities>(new InjectionConstructor());
IOC.Container.RegisterType<IRepository, GenericRepository>
    ("Customer", new InjectionConstructor(typeof(CustomerEntities)));

IOC.Container.RegisterType<IClientModel, ClientModel>();
IOC.Container.RegisterType<ICustomerModel, CustomerModel>();

But then when I want to resolve this (to use the IRepository) I have to do a manual resolve like this:

public ClientModel(IUnityContainer container)
{
   this.dataAccess = container.Resolve<IRepository>(Client);

   .....
}

What I would like to do is to have it resolved in the constructor (just like IUnityContainer). I need some way to say which named type to resolve to.

Something like this: (NOTE: Not real code)

public ClientModel([NamedDependancy("Client")] IRepository dataAccess)
{
   this.dataAccess = dataAccess;

   .....
}

Is there a way to make my fake code work?

Seriocomic answered 12/8, 2011 at 21:58 Comment(0)
K
104

You can configure dependencies with or without names in the API, attributes, or via the config file. You didn't mention XML above, so I'll assume you're using the API.

To tell the container to resolve a named dependency, you'll need to use an InjectionParameter object. For your ClientModel example, do this:

container.RegisterType<IClientModel, ClientModel>(
    new InjectionConstructor(                        // Explicitly specify a constructor
        new ResolvedParameter<IRepository>("Client") // Resolve parameter of type IRepository using name "Client"
    )
);

This tells the container "When resolving ClientModel, call the constructor that takes a single IRepository parameter. When resolving that parameter, resolve with the name 'Client' in addition to the type."

If you wanted to use attributes, your example almost works, you just need to change the attribute name:

public ClientModel([Dependency("Client")] IRepository dataAccess)
{
   this.dataAccess = dataAccess;

   .....
}
Kokura answered 13/8, 2011 at 6:19 Comment(2)
Is it possible to make it work without the dependency attribute? For example the IRepository>("Customer") should be injected in another instance of ClientModelValdovinos
@Valdovinos sure,using the API. Create a separate named registration for ClientModel for each variation of injection style you need,, then resolve the dependency on IClientModel. Works the same as it does for IRepository above.Kokura
D
29

This is a very late response but the question still shows up in Google.

So anyways, 5 years later...

I have a pretty simple approach. Usually when you need to use "named dependency" it's because you're trying to implement some kind of strategy pattern. In that case, I simply create a level of indirection between Unity and the rest of my code called the StrategyResolver to not be directly depending on Unity.

public class StrategyResolver : IStrategyResolver
{
    private IUnityContainer container;

    public StrategyResolver(IUnityContainer unityContainer)
    {
        this.container = unityContainer;
    }

    public T Resolve<T>(string namedStrategy)
    {
        return this.container.Resolve<T>(namedStrategy);
    }
}

Usage:

public class SomeClass: ISomeInterface
{
    private IStrategyResolver strategyResolver;

    public SomeClass(IStrategyResolver stratResolver)
    {
        this.strategyResolver = stratResolver;
    }

    public void Process(SomeDto dto)
    {
        IActionHandler actionHanlder = this.strategyResolver.Resolve<IActionHandler>(dto.SomeProperty);
        actionHanlder.Handle(dto);
    }
}

Registration:

container.RegisterType<IActionHandler, ActionOne>("One");
container.RegisterType<IActionHandler, ActionTwo>("Two");
container.RegisterType<IStrategyResolver, StrategyResolver>();
container.RegisterType<ISomeInterface, SomeClass>();

Now, the nice thing about this is that I will never have to touch the StrategyResolver ever again when adding new strategies in the future.

It's very simple. Very clean and I kept the dependency on Unity to a strict minimum. The only time I would have touch the StrategyResolver is if I decide to change container technology which is very unlikely to happen.

Hope this helps!

Edit: I don't really like the accepted answer because when you use the Dependency attribute in your service's constructor you actually have a hard dependency on Unity. The Dependency attribute is part of the Unity library. At that point you might as well pass an IUnityContainer dependency everywhere.

I prefer having my service classes depend on objects that I completely own instead of having a hard dependency on an external library all over the place. Also using Dependency attribute makes the constructors signatures less clean and simple.

Furthermore, this technique allows to resolve named dependencies at runtime without having to hardcode the named dependencies in the constructor, in the application configuration file or use InjectionParameter which are all methods that require to know what named dependency to use at design time.

Edit (2016-09-19): For those that might wonder, the container will know to pass itself when you are requesting IUnityContainer as dependency, as shown in the StrategyResolver constructor signature.

Edit (2018-10-20): Here's another way, simply using a factory:

public class SomeStrategyFactory : ISomeStrategyFactory
{
    private IStrategy _stratA;
    private IStrategy _stratB;

    public SomeFactory(IStrategyA stratA, IStrategyB stratB)
    {
        _stratA = stratA;
        _stratB = stratB;
    }

    public IStrategy GetStrategy(string namedStrategy){
        if (namedStrategy == "A") return _stratA;
        if (namedStrategy == "B") return _stratB;
    }
}

public interface IStrategy {
    void Execute();
}

public interface IStrategyA : IStrategy {}

public interface IStrategyB : IStrategy {}

public class StrategyA : IStrategyA {
    public void Execute(){}
}

public class StrategyB : IStrategyB {
    public void Execute() {}
}

Usage:

public class SomeClass : ISomeClass
{
    public SomeClass(ISomeStrategyFactory strategyFactory){

        IStrategy strat = strategyFactory.GetStrategy("HelloStrategy");
        strat.Execute();

    }
}

Registration:

container.RegisterType<ISomeStrategyFactory, SomeStrategyFactory>();
container.RegisterType<IStrategyA, StrategyA>();
container.RegisterType<IStrategyB, StrategyB>();
container.RegisterType<ISomeClass, SomeClass>();

This 2nd suggestion is the same thing but using the factory design pattern.

Hope this helps!

Deepfry answered 17/6, 2016 at 12:58 Comment(8)
I like this pattern better than InjectionConstructor but isn't it Service Locator hidden behind StrategyResolver?Eliathan
It does look like some form of service locator but then again I think it is not. You're only using the StrategyResolver as a helper to implement the strategy pattern end of story. The StrategyResolver is not your dependency injection container. If you start doing something as perverse as loading all your dependencies as named dependencies and using the StrategyResolver to find them then yes, in that case, you are truly just using this as a service locator anti-pattern. If you don't abuse and stick to its purpose then it makes your code beautiful with no dependency on your DI technology.Deepfry
The StrategyResolver is registered as a dependency in your container. The dependency is injected through the constructor. If your current class is registered in your container then your container will be able to inject the dependencies you need by looking at your classes constructor parameters.Deepfry
An improvement to this (in order to limit the misuse) could be to restrict the IStrategyResolver interface. Basically, instead of being able to resolve any T you could just have a method IActionHandler ResolveMyStrategy(string strategyName).Promising
@Botis I like it. Thumbs up!Deepfry
My two cents... I've implemented something along these lines, but instead of passing the IUnityContainer to the resolver type, I've used a Func<string, ISomeInterface> resolver as constructor argument. So you can delegate the resolution to the DI project module and therefore being agnostic of the container used. Registration: container.RegisterInstance<IStrategyResolver>(new StrategyResolver(key => container.Resolve<ISomeInteface>(key))). Also this approach is more restrictive agains a possible Service Locator misuse.Civic
nice approach! you saved my day.Modernistic
It took me a few read-overs to appreciate this. But now I do. It seems to me to be a stepped up Factory Pattern (where dto.SomeProperty is the factory-"key").........but the .Resolve is still taking place with Unity. Anyway...thanks for posting........Parget
D
4

You should be able to use ParameterOverrides

var repository = IOC.Container.Resolve<IRepository>("Client");
var clientModel = IOC.Container.Resolve<ClientModel>(new ParameterOverrides<ClientModel> { {"dataAccess", repository } } );

edit: I'm not sure why you're passing around the UnityContainer - personally, we inject our dependencies into the constructor themselves (which is "normal" from what I've seen). But regardless, you can specify a name in your RegisterType and Resolve methods.

IOC.Container.RegisterType<IRepository, GenericRepository>("Client");
IOC.Container.Resolve<IRepository>("Client");

and it will give you the type you registered for that name.

Detail answered 12/8, 2011 at 22:59 Comment(3)
That would work, but it means that the level that knows about the clientModel also needs to know what a repository is and looks like. I need the repository abstracted away from the level that knows about the 'clientModel'. (In fact the whole point of the clientModel is to make the repository abstract to my Service Layer.Seriocomic
I want to inject right into the constructor. (That is the point of this question.). I just have 2 IRepository mappings. I am looking for a way to help unity distinguish between them.Seriocomic
@Kyle - specifying names on the resolve call isn't transitive - resolving <ClientModel, "Client"> won't automatically resolve <IRepository, "Client">. There will need to be configuration in the container to use the correct names.Kokura
C
3

Don't do this - just create a class ClientRepository : GenericRepository { } and utilise the Type system.

Croatian answered 31/7, 2018 at 10:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.