Die Injektion mehrere Implementierungen mit Dependency injection
Ich bin momentan an einem ASP.NET Kern-Projekt und wollen, verwenden Sie die integrierte Dependency Injection (DI) - Funktionalität.
Gut, angefangen habe ich mit einem interface:
ICar
{
string Drive();
}
und umsetzen wollen, die ICar
- Schnittstelle, die mehrere Male wie
public class BMW : ICar
{
public string Drive(){...};
}
public class Jaguar : ICar
{
public string Drive(){...};
}
und fügen Sie den folgenden in der Startup
Klasse
public void ConfigureServices(IServiceCollection services)
{
//Add framework services.
services.AddMvc();
services.AddTransient<ICar, BMW>();
//or
services.AddTransient<ICar, Jaguar>();
}
Nun muss ich eine Entscheidung zwischen beiden Implementierungen und meine Klasse entschieden wird in jedem Konstruktor muss ein ICar Umsetzung. Aber meine Idee war zu sagen, wenn der angeforderte Controller ist BMWController, dann verwenden Sie BMW-Implementierung oder verwenden Sie Jaguar-wenn die JaguarController angefordert.
Sonst DI machen keinen Sinn für mich. Wie kann ich damit umgehen, richtig?
Zum besseren Verständnis mein problem werfen Sie einen Blick auf dieses Bild: https://media-www-asp.azureedge.net/media/44907/dependency-injection-golf.png?raw=true
Wie funktioniert die dependency resolver arbeiten und wo kann ich es einrichten in ASP.NET Core?
In der Einheit es ist möglich, etwas wie dies
container.RegisterType<IPerson, Male>("Male");
container.RegisterType<IPerson, Female>("Female");
und nennen Sie die richtige Art, wie diese
[Dependency("Male")]IPerson malePerson
- Ich denke, dass die Idee falsch ist. Wenn Sie BMWController, die braucht konkrete Auto-Implementierung injizieren von ICar hat keinen Sinn, dass die Magie von DI - Sie sagen: "gimme Umsetzung der Ikar" und egal, was es ist. Ich würde bereiten Sie eine separate Schnittstelle:
interface IBmwCar: ICar { ... }
und injizieren es inBMWController
. Andere Idee ist, erstellen Sie factory. f.eclass CarFactory : ICarFactory { ICar GimmeCar<TController>() }
wo Sie zugeordnet haben, controller-Typ um die konkrete Umsetzung. - Danke für die Antwort.
- Ist es nicht ein überlauf-Schnittstellen, wenn ich die user so etwas wie IBmwCar : ICar für alle Marken, die ich umsetzen will? Ich habe nur die Festplatte als Methode und nicht irgendeine andere. Naja, ich würde dann IBMW, IJaguar... mit der gleichen Signatur wie das ICar und und mit einer Anweisung, wie diese für jede Marke, die ich umgesetzt haben: die Dienstleistungen.AddTransient<IJaguar, Jaguar>(); Natürlich könnte ich mit Factory-Muster, aber gibt es nicht irgendeine Lösung, um meine Arbeit zu tun, mit DI?
- eine Sache, über die DI ist, können Sie eine Abhängigkeit IEnumerable<ICar> und alle Implementierungen, die registriert wurden, wenn keine Implementierungen registriert haben, erhalten Sie eine leere Liste, anstatt einen Fehler zu beheben. Also, wenn Ikar hat eine id-Eigenschaft, die Sie finden konnte, die Sie brauchen in der Liste.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Die Funktionalität, die Sie suchen ist nicht einfach zu implementieren, zumindest dann, wenn Sie es in den controller, weil die Controller behandelt werden, ein bisschen speziell (standardmäßig Controller nicht registriert
ServiceCollection
und daher nicht behoben wird/instanziiert der container und stattdessen instanziiert ASP.NET Kern während der Anfrage, siehe auch die Erläuterung und Beispiel auf meine zugehörige Antwort).Mit integrierten IoC-container können Sie nur über die factory-Methode, hier mit einem Beispiel auf eine
BmwCarFactory
Klasse:Den Standard IoC-container ist absichtlich einfach gehalten, um bieten die Grundlagen von dependency injection, um Ihnen den Einstieg und für die anderen IoC-Container werden in der Lage, leicht-plugin gibt, und ersetzen Sie die Standard-Implementierung.
Für komplexere Szenarien die Nutzer sind aufgefordert, ein IoC von Ihrer Wahl, die unterstützt erweiterte Funktionen (assembly Scannen, Dekorateure, bedingte/parametrisierten Abhängigkeiten, etc.
AutoFac (welches ich in meinen Projekten) unterstützt eine solche erweiterte Szenarien. In der AutoFac-Dokumentation gibt es 4 Szenarien (zusammen mit der 3., die @pwas vorgeschlagen, in den Kommentaren):
1. Neugestaltung Ihrer Klassen
Braucht einige zusätzliche overhead-refactoring-code und Klassen-Hierarchie, jedoch stark vereinfacht, der Verbrauch von injizierten services
2. Ändern Sie die Eintragungen
Den docs beschreiben hier, wenn Sie nicht Willens oder nicht in der Lage den code zu ändern.
3. Mit ausgestanzten services (hier)
Es ist ziemlich ähnlich zu der vorherigen Vorgehensweise-2. aber löst der Dienstleistungen basiert auf einem Schlüssel, statt über Ihre konkreten Typ
4. Verwenden Sie Metadaten
Dies ist ganz ähnlich wie 3. aber Sie definieren die keys per Attribut.
Anderen Container wie Einheit haben spezielle Attribute, wie
DependencyAttribute
die Sie verwenden können, um kommentieren Sie die Abhängigkeit, wieAber diese und die 4. option von Autofac machen den IoC-container Leck in Ihre Dienste, und Sie sollten die anderen Ansätze.
Alternativ können Sie Klassen erstellen und Fabriken, die lösen Ihre Dienstleistungen basierend auf einigen conventions. Zum Beispiel ein
ICarFactory
:Dann verwenden Sie es wie
Alternative zu IServiceProvider
IEnumerable<ICar>
zu vermeiden, die Abhängigkeit von der containerIUserRepository
entwederSqliteUserRepository
undSqlServerUserRepositrory
und Sie nur registrieren zählt es. Wenn Sie sich registrieren, mehrfachregistrierungen können Sie nicht ohne weiteres injizieren Sie je nach Kontext oder Sie beheben alle von Ihnen mitIEnumerable<T>
. Also, wenn Sie wollen, um passIBmwCar
w/o Verwendung der anderen Optionen, dann es sollte ja auch nur eine Umsetzung