2014-12-19 6 views
7

Für folgende Schnittstellen und Klassen, wie verwende ich Unity Container zu Fliessend (programmatisch) Draht es so nach oben, dass FooController bekommt eine Instanz von ARepository und BarController eine Instanz von BRepository über Konstruktor Injektion bekommt?Constructor Injektion mehrere Implementierungen in Unity Container

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) 
    { 
    } 
} 
+0

Die dup Frage sieht anders aus, aber die Antwort ist genau das gleiche. – jgauffin

+0

Hier ist ein weiterer, wo die Antwort funktioniert: http://stackoverflow.com/questions/4989676/injecting-a-specific-instance-of-an-interface-using-autofac – jgauffin

Antwort

1

Eine Möglichkeit ist, die spezifische Art registrieren durch die UnityContainer gelöst werden, wenn IRepository Lösung:

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

Mit diesem abhängt, ob Sie benötigen feinkörnige Kontrolle darüber, welche Arten in bestimmten Kontexten gelöst werden - wenn Sie das tun, könnten Sie eine lokale IUnityContainer Instanz und unter Verwendung von RegisterInstance() statt:

//Assumes container is instantiated and already populated with other instances/type mappings. 
IUnityContainer childContainer = container.CreateChildContainer(); 
container.RegisterInstance<IRepository>(new BRepository(), new ContainerControlledLifetimeManager()); 
2

Sie können dies zur Registrierungszeit erreichen, indem Sie jeder Controllerregistrierung mitteilen, wie die Konstruktorparameter aufgelöst werden sollen.

3

Ich würde dringend empfehlen gegen einen dedizierten/lokalen/injizierten UnityContainer für jeden Typ wie eines der vorgeschlagenen Poster zu erstellen.

Dies kann auf zwei Arten angegangen werden.

Eines wird durch das Definieren der Auflösung in Registrierungszeit als TylerOhlsen vorgeschlagen. obwohl Dies ist eine gute Lösung, wenn Sie später registrieren beide ARepository und BRepository als Implementierungen für IRepository, müssen Sie noch mit der Tatsache umgehen, müssen Sie zwei implenetations für die gleiche Schnittstelle, und wenn eine dritte Klasse eines Tages erfordern eine Implementierung IRepository, ohne es speziell in der Registrierung zu definieren, wird es eine unvorhersehbare Instanz erhalten.

Die zweite Option, die etwas sicherer ist, ist die Registrierung einer Fabrik für IRepository. Das einfachste Beispiel wäre eine Zeichenfolge als Schlüssel verwendet wird, wie folgt aus:

// 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"); 

Dann bei der Umsetzung von FooController und BarController die func Fabrik durch Injektion erhalten und die richtige Instanz auswählen.

public class FooController 
{ 
    IRepository repository; 

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

Sie können hier mehr über diese Zeilen lesen: http://msdn.microsoft.com/en-us/library/ff660854%28v=pandp.20%29.aspx

2

Sie können den Typ mit einem Namen registrieren, und dann, dass Klassen in einem Dependency Attribut der Ziel verwenden:

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

Dann Deklarieren Sie im FooController und BarController, welche Implementierung Sie mit dem Attribut Dependency benötigen:

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

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

Sie können sowohl eine public const string in ARepository und BRepository statt "A" und "B" in RegisterType und Dependency verwenden.

+1

nicht den gesamten Zweck der Verwendung zu besiegen Abhängigkeitsinjektion, wenn wir die Abhängigkeit von der Klasse angeben und nicht von einem Konfirmator oder etwas? – Ruchan

+1

Die Klasse gibt an, dass sie einen bestimmten "Geschmack" von IService benötigt, aber der tatsächliche IService-Typ, der instanziiert wird, wird zur Laufzeit aufgelöst und hängt davon ab, wie die Typen registriert sind. – PeteB

0

JoefGoldstein habe mich am meisten, aber ich habe ein paar Fehler, wenn ich das versuche.

Ich musste meine Klassen mit einer benannten Abhängigkeit registrieren und die InjectionFactory-Klasse verwenden, um die Abhängigkeit aufzulösen.

// 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))) 
); 

Da ist in meinem Controller

public class FooController 
{ 
    IRepository repository; 

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