Wie löse ich einen Typ manuell mithilfe des in ASP.NET Core MVC integrierten Frameworks für die Abhängigkeitsinjektion auf?
Das Aufstellen des Containers ist einfach genug:
public void ConfigureServices(IServiceCollection services)
{
// ...
services.AddTransient<ISomeService, SomeConcreteService>();
}
Aber wie kann ich das Problem beheben, ISomeService
ohne eine Injektion durchzuführen? Zum Beispiel möchte ich dies tun:
ISomeService service = services.Resolve<ISomeService>();
Es gibt keine solchen Methoden in IServiceCollection
.
ConfigureServices()
Methode (mitIServiceCollection
) oder irgendwo in der Anwendung auflösen ?Antworten:
Die
IServiceCollection
Schnittstelle wird zum Erstellen eines Abhängigkeitsinjektionscontainers verwendet. Nachdem es vollständig erstellt wurde, wird es zu einerIServiceProvider
Instanz zusammengesetzt, mit der Sie Dienste auflösen können. Sie können eineIServiceProvider
in jede Klasse injizieren . Die KlassenIApplicationBuilder
undHttpContext
können den Dienstanbieter auch über ihreApplicationServices
bzw.RequestServices
Eigenschaften bereitstellen .IServiceProvider
definiert eineGetService(Type type)
Methode zum Auflösen eines Dienstes:Es stehen auch verschiedene praktische Erweiterungsmethoden zur Verfügung, z. B.
serviceProvider.GetService<IFooService>()
(einusing
für hinzufügenMicrosoft.Extensions.DependencyInjection
).Auflösen von Diensten innerhalb der Startklasse
Abhängigkeiten einfügen
Die Laufzeit der Hosting - Service - Provider können bestimmte Dienste in den Konstruktor der injizieren
Startup
Klasse, wieIConfiguration
,IWebHostEnvironment
(IHostingEnvironment
in Pre-3.0 - Versionen),ILoggerFactory
undIServiceProvider
. Beachten Sie, dass letztere eine von der Hosting-Schicht erstellte Instanz ist und nur die wesentlichen Dienste zum Starten einer Anwendung enthält .Die
ConfigureServices()
Methode erlaubt kein Injizieren von Diensten, sondern akzeptiert nur einIServiceCollection
Argument. Dies ist sinnvoll, daConfigureServices()
Sie hier die für Ihre Anwendung erforderlichen Dienste registrieren. Sie können hier jedoch Dienste verwenden, die in den Konstruktor des Startups eingefügt wurden, zum Beispiel:Alle in registrierten Dienste
ConfigureServices()
können dann in dieConfigure()
Methode eingefügt werden. Sie können nach demIApplicationBuilder
Parameter eine beliebige Anzahl von Diensten hinzufügen :Abhängigkeiten manuell auflösen
Wenn Sie manuell lösen Dienste benötigen, sollten Sie vorzugsweise die Verwendung der
ApplicationServices
von einerIApplicationBuilder
in demConfigure()
Verfahren:Es ist möglich, ein
IServiceProvider
im Konstruktor IhrerStartup
Klasse zu übergeben und direkt zu verwenden , aber wie oben enthält dieses eine begrenzte Teilmenge von Diensten und hat daher einen begrenzten Nutzen:Wenn Sie Dienste in der
ConfigureServices()
Methode auflösen müssen , ist ein anderer Ansatz erforderlich. Sie könnenIServiceProvider
aus derIServiceCollection
Instanz ein Zwischenprodukt erstellen, das die bis zu diesem Zeitpunkt registrierten Dienste enthält :Bitte beachten Sie: Im Allgemeinen sollten Sie das Auflösen von Diensten innerhalb der
ConfigureServices()
Methode vermeiden , da dies tatsächlich der Ort ist, an dem Sie die Anwendungsdienste konfigurieren . Manchmal benötigen Sie nur Zugriff auf eineIOptions<MyOptions>
Instanz. Sie können dies erreichen, indem Sie die Werte von derIConfiguration
Instanz an eine Instanz von bindenMyOptions
(was im Wesentlichen das Options-Framework tut):Das manuelle Auflösen von Diensten (auch als Service Locator bezeichnet) wird im Allgemeinen als Anti-Pattern angesehen . Obwohl es Anwendungsfälle gibt (für Frameworks und / oder Infrastrukturschichten), sollten Sie dies so weit wie möglich vermeiden.
quelle
IServiceCollection
Klasse injizieren lassen, eine Klasse, die manuell erstellt wird ( außerhalb des Bereichs der mittleren Ware ), in meinem Fall ein Scheduler, der regelmäßig einige Dienste zum Generieren benötigt und senden Sie eine E-Mail.ConfigureServices
und dieser Dienst ein Singleton ist, handelt es sich um einen anderen Singleton als den von IhnenController
verwendeten! Ich nehme an, das liegt daran, dass es eine andere verwendetIServiceProvider
- um dies zu vermeiden, lösen Sie NICHT überBuildServiceProvider
und verschieben Sie stattdessen Ihre Suche nach dem Singleton vonConfigureServices
nachConfigure(..other params, IServiceProvider serviceProvider)
inStartup.cs
IServiceProvider
Instanz handelt, wird eine neue Singleton-Instanz erstellt. Sie können dies vermeiden, indem Sie die Dienstanbieterinstanz von derConfigureServices
Methode zurückgeben, sodass dies auch der Container ist, den Ihre Anwendung verwendet.collection.BuildServiceProvider();
war das, was ich brauchte, danke!Das manuelle Auflösen von Instanzen umfasst die Verwendung der
IServiceProvider
Schnittstelle:Auflösen der Abhängigkeit in Startup.ConfigureServices
Auflösen von Abhängigkeiten in Startup.Configure
Auflösen von Abhängigkeiten in Startup.Configure in ASP.NET Core 3
Verwenden von Runtime Injected Services
Einige Typen können als Methodenparameter eingefügt werden:
Auflösen von Abhängigkeiten in Controller-Aktionen
quelle
GetService
was generisch ist, ist eine Erweiterungsmethode imMicrosoft.Extensions.DependencyInjection
Namespace.Wenn Sie eine Anwendung mit einer Vorlage generieren, wird Folgendes in der
Startup
Klasse angezeigt:Dort können Sie dann Abhängigkeiten hinzufügen, zum Beispiel:
Wenn Sie
ITestService
auf Ihrem Controller zugreifen möchten, können SieIServiceProvider
den Konstruktor hinzufügen und er wird injiziert:Anschließend können Sie den hinzugefügten Dienst auflösen:
Beachten Sie, dass Sie zur Verwendung der generischen Version den Namespace in die Erweiterungen aufnehmen müssen:
ITestService.cs
TestService.cs
Startup.cs (ConfigureServices)
HomeController.cs
quelle
Wenn Sie nur eine Abhängigkeit auflösen müssen, um sie an den Konstruktor einer anderen von Ihnen registrierten Abhängigkeit zu übergeben, können Sie dies tun.
Angenommen, Sie hatten einen Dienst, der eine Zeichenfolge und einen ISomeService aufgenommen hat.
Wenn Sie dies in Startup.cs registrieren, müssen Sie Folgendes tun:
quelle
ISomeService
war aber immer noch null für mich.Auf diese Weise können Sie Abhängigkeiten in Attribute wie AuthorizeAttribute einfügen
quelle
Ich weiß, dass dies eine alte Frage ist, aber ich bin erstaunt, dass ein ziemlich offensichtlicher und ekelhafter Hack nicht hier ist.
Sie können die Möglichkeit nutzen, Ihre eigene ctor-Funktion zu definieren, um die erforderlichen Werte aus Ihren Diensten abzurufen, während Sie sie definieren. Dies wird natürlich jedes Mal ausgeführt, wenn der Dienst angefordert wurde, es sei denn, Sie entfernen / löschen die Definition von explizit und fügen sie erneut hinzu Dieser Service innerhalb des ersten Aufbaus des ausbeutenden Ctors .
Diese Methode hat den Vorteil, dass Sie den Servicebaum während der Konfiguration des Service nicht erstellen oder verwenden müssen. Sie definieren noch, wie Dienste konfiguriert werden.
Die Möglichkeit, dieses Muster zu beheben, besteht darin,
OtherService
eine explizite Abhängigkeit von anzugebenIServiceINeedToUse
, anstatt entweder implizit von ihm oder dem Rückgabewert seiner Methode abhängig zu sein ... oder diese Abhängigkeit explizit auf eine andere Weise aufzulösen.quelle
quelle