9

For the following interfaces and classes, how do I use Unity Container to Fluently (programatically) wire it up so that FooController gets an instance of ARepository and BarController gets an instance of BRepository via constructor injection?

public interface IRepository
{
}

public class ARepository : IRepository
{
}

public class BRepository : ARepository
{
}

public class FooController
{
    public FooController(IService service, IRepository repository)
    {
    }
}

public class BarController
{
    public BarController(IService service, IRepository repository)
    {
    }
}
Sebastian Patten
  • 7,157
  • 4
  • 45
  • 51
  • The dup question looks different, but the answer is exactly the same. – jgauffin Aug 30 '16 at 06:20
  • Here is another one where the answer works: http://stackoverflow.com/questions/4989676/injecting-a-specific-instance-of-an-interface-using-autofac – jgauffin Aug 30 '16 at 06:20

5 Answers5

3

You can achieve this at registration time by telling each controller registration how to resolve its constructor parameters.

container.RegisterType<FooController>(new InjectionConstructor(
    new ResolvedParameter<IService>(), new ResolvedParameter<ARepository>());

container.RegisterType<BarController>(new InjectionConstructor(
    new ResolvedParameter<IService>(), new ResolvedParameter<BRepository>());
TylerOhlsen
  • 5,485
  • 1
  • 24
  • 39
3

I would highly recommend against creating a dedicated/local/injected UnityContainer for each type like one of the posters suggested.

This can be approached in two ways.

One is by specifically defining the resolving in registration time as TylerOhlsen suggested. This is a good solution, though if you register later both ARepository and BRepository as implementations for IRepository, you still need to deal with the fact you have two implenetations for the same interface, and if a third class will someday require an implementation of IRepository, without defining it specifically in the registration, it will get an unpredictable instance.

The second option, which is slightly safer, is registering a factory for IRepository. The simplest example would be using a string as the key, like this:

// Create a resolver(abstract factory) for the IRepository interface type
var resolver = myContainer.Resolve<Func<IRepository>>();

// ... other code here...

// Register mappings for the IRepository interface to appropriate concrete types
myContainer.RegisterType<IRepository, ARepository>("A");
myContainer.RegisterType<IRepository, BRepository>("B");

Then in the implementation of FooController and BarController receive the func factory by injection and select the right instance.

public class FooController
{
   IRepository repository;

   public FooController(IService service, Func<IRepository> repositoryFactory)
   {
       repository = repositoryFactory("A");
   }
}

You can read more about this here: http://msdn.microsoft.com/en-us/library/ff660854%28v=pandp.20%29.aspx

3

You can register the type with a name and then use that in a Dependency attribute of the target classes:

// Register mappings for the IRepository interface to appropriate concrete types
myContainer.RegisterType<IRepository, ARepository>("A");
myContainer.RegisterType<IRepository, BRepository>("B");

Then in the FooController and BarController, declare which implementation you require with the Dependency attribute:

public class FooController
{
    public FooController(IService service, [Dependency("A")] IRepository repository)
    {
    }
}

public class BarController
{
    public BarController(IService service, [Dependency("B")] IRepository repository)
    {
    }
}

You can use a public const string in ARepository and BRepository rather than "A" and "B" in both RegisterType and Dependency.

PeteB
  • 151
  • 1
  • 12
  • 2
    doesn't it defeat the whole purpose of using dependency injection if we state the dependency on class rather than a confirgurator or something? – Ruchan Dec 22 '15 at 08:22
  • 2
    The class is stating that it needs a particular "flavour" of IService but the actual IService type which is instantiated is resolved at runtime and dependant on how the types are registered. – PeteB Jan 14 '16 at 21:19
1

One possibility is to register the specific type to be resolved by the UnityContainer when resolving IRepository:

IUnityContainer container = new UnityContainer();
container.RegisterType<IRepository, BRepository>(new ContainerControlledLifetimeManager());

Using this depends on whether you require finer grained control over what types are resolved in certain contexts - if you do, you might consider using a local IUnityContainer instance and using RegisterInstance() instead:

//Assumes container is instantiated and already populated with other instances/type mappings.
IUnityContainer childContainer = container.CreateChildContainer();
container.RegisterInstance<IRepository>(new BRepository(), new ContainerControlledLifetimeManager());
toadflakz
  • 7,764
  • 1
  • 27
  • 40
1

JoefGoldstein got me most of the way, but I got a few errors when attempting that.

I had to register my classes with a named dependency and use the InjectionFactory class to resolve the dependency.

// register interfaces to implementations with a named dependency 
myContainer.RegisterType<IRepository, ARepository>("A");
myContainer.RegisterType<IRepository, BRepository>("B");

// register Injection factory to resolve the dependency
container.RegisterType<Func<string, IRepository>>(
            new InjectionFactory(c =>
            new Func<string, IRepository>(name => c.Resolve<IRepository>(name)))
);

Then in my controller

public class FooController
{
   IRepository repository;

   public FooController(IService service, Func<string, IRepository> repositoryFactory)
   {
       repository = repositoryFactory("A");
   }
}
dannash918
  • 434
  • 6
  • 14