Comment résoudre manuellement un type à l'aide de l'infrastructure d'injection de dépendances intégrée ASP.NET Core MVC?
La mise en place du conteneur est assez simple:
public void ConfigureServices(IServiceCollection services)
{
// ...
services.AddTransient<ISomeService, SomeConcreteService>();
}
Mais comment puis-je résoudre ISomeService
sans effectuer d'injection? Par exemple, je veux faire ceci:
ISomeService service = services.Resolve<ISomeService>();
Il n'y a pas de telles méthodes dans IServiceCollection
.
ConfigureServices()
méthode (avecIServiceCollection
) ou n'importe où dans l'application?Réponses:
L'
IServiceCollection
interface est utilisée pour créer un conteneur d'injection de dépendances. Une fois entièrement construit, il se compose d'uneIServiceProvider
instance que vous pouvez utiliser pour résoudre les services. Vous pouvez injecter unIServiceProvider
dans n'importe quelle classe. Les classesIApplicationBuilder
etHttpContext
peuvent également fournir le fournisseur de services, via leurs propriétésApplicationServices
ouRequestServices
.IServiceProvider
définit uneGetService(Type type)
méthode pour résoudre un service:Il existe également plusieurs méthodes d'extension pratiques, telles que
serviceProvider.GetService<IFooService>()
(ajouter unusing
pourMicrosoft.Extensions.DependencyInjection
).Résolution des services dans la classe de démarrage
Injection de dépendances
Le fournisseur de services d' hébergement de l'exécution peut injecter certains services dans le constructeur de la
Startup
classe, par exempleIConfiguration
,IWebHostEnvironment
(IHostingEnvironment
en version pré-3.0),ILoggerFactory
etIServiceProvider
. Notez que cette dernière est une instance construite par la couche d'hébergement et ne contient que les services essentiels pour démarrer une application .La
ConfigureServices()
méthode n'autorise pas l'injection de services, elle accepte uniquement unIServiceCollection
argument. Cela est logique carConfigureServices()
c'est là que vous enregistrez les services requis par votre application. Cependant, vous pouvez utiliser ici les services injectés dans le constructeur du démarrage, par exemple:Tous les services enregistrés dans
ConfigureServices()
peuvent alors être injectés dans laConfigure()
méthode; vous pouvez ajouter un nombre arbitraire de services après leIApplicationBuilder
paramètre:Résolution manuelle des dépendances
Si vous devez résoudre manuellement des services, vous devez de préférence utiliser le
ApplicationServices
fourni parIApplicationBuilder
dans laConfigure()
méthode:Il est possible de passer et d'utiliser directement un
IServiceProvider
dans le constructeur de votreStartup
classe, mais comme ci - dessus, cela contiendra un sous-ensemble limité de services , et a donc une utilité limitée:Si vous devez résoudre des services dans la
ConfigureServices()
méthode, une approche différente est requise. Vous pouvez créer un intermédiaire àIServiceProvider
partir de l'IServiceCollection
instance qui contient les services qui ont été enregistrés jusqu'à ce point :Remarque: En règle générale, vous devez éviter de résoudre les services dans la
ConfigureServices()
méthode, car c'est en fait l'endroit où vous configurez les services d'application. Parfois, vous avez juste besoin d'accéder à uneIOptions<MyOptions>
instance. Vous pouvez accomplir cela en liant les valeurs de l'IConfiguration
instance à une instance deMyOptions
(ce qui est essentiellement ce que fait le cadre d'options):Les services de résolution manuelle (aka Service Locator) sont généralement considérés comme un anti-modèle . Bien qu'il ait ses cas d'utilisation (pour les couches d'infrastructure et / ou d'infrastructure), vous devez l'éviter autant que possible.
la source
IServiceCollection
injecté, une classe qui est créée manuellement ( hors de la portée du middleware ), un planificateur dans mon cas, qui a périodiquement besoin de certains services pour générer et envoyer un e-mail.ConfigureServices
et que ce service est un singleton, ce sera un singleton différent de celui que vousController
utilisez! Je suppose que cela est dû au fait qu'il utilise un autreIServiceProvider
- pour éviter ce ne résolvent pas parBuildServiceProvider
et au lieu déplacer votre recherche du singleton deConfigureServices
àConfigure(..other params, IServiceProvider serviceProvider)
enStartup.cs
IServiceProvider
instance différente , il créera une nouvelle instance singleton. Vous pouvez éviter cela en renvoyant l'instance de fournisseur de services à partir de laConfigureServices
méthode afin que ce soit le conteneur que votre application utilise également.collection.BuildServiceProvider();
était ce dont j'avais besoin, merci!La résolution manuelle des instances implique l'utilisation de l'
IServiceProvider
interface:Résolution de la dépendance dans Startup.ConfigureServices
Résolution des dépendances au démarrage.
Résolution des dépendances dans Startup.Configure dans ASP.NET Core 3
Utilisation des services injectés à l'exécution
Certains types peuvent être injectés en tant que paramètres de méthode:
Résolution des dépendances dans les actions du contrôleur
la source
GetService
qui est générique est une méthode d'extension dans l'Microsoft.Extensions.DependencyInjection
espace de noms.Si vous générez une application avec un modèle, vous allez avoir quelque chose comme ça dans la
Startup
classe:Vous pouvez ensuite y ajouter des dépendances, par exemple:
Si vous souhaitez accéder
ITestService
sur votre contrôleur, vous pouvez ajouterIServiceProvider
le constructeur et il sera injecté:Ensuite, vous pouvez résoudre le service que vous avez ajouté:
Notez que pour utiliser la version générique, vous devez inclure l'espace de noms avec les extensions:
ITestService.cs
TestService.cs
Startup.cs (ConfigureServices)
HomeController.cs
la source
Si vous avez juste besoin de résoudre une dépendance dans le but de la transmettre au constructeur d'une autre dépendance que vous enregistrez, vous pouvez le faire.
Supposons que vous disposiez d'un service qui a pris une chaîne et un ISomeService.
Lorsque vous allez l'enregistrer dans Startup.cs, vous devrez le faire:
la source
ISomeService
c'était toujours nul pour moi.Vous pouvez injecter des dépendances dans des attributs comme AuthorizeAttribute de cette manière
la source
Je sais que c'est une vieille question, mais je suis étonné qu'un hack plutôt évident et dégoûtant ne soit pas là.
Vous pouvez exploiter la possibilité de définir votre propre fonction ctor pour récupérer les valeurs nécessaires de vos services au fur et à mesure que vous les définissez ... évidemment, cela serait exécuté à chaque fois que le service était demandé, sauf si vous supprimez / effacez explicitement et rajoutez la définition de ce service dans la première construction du ctor exploitant .
Cette méthode a l'avantage de ne pas vous obliger à construire l'arborescence du service, ou à l'utiliser, lors de la configuration du service. Vous définissez toujours comment les services seront configurés.
La manière de corriger ce modèle serait de donner
OtherService
une dépendance explicite àIServiceINeedToUse
, plutôt que de dépendre implicitement de lui ou de la valeur de retour de sa méthode ... ou de résoudre cette dépendance explicitement d'une autre manière.la source
la source