Injection de dépendance avec des classes autres qu’une classe de contrôleur

À ce stade, j’injecte facilement des éléments dans mes contrôleurs, dans certains cas, je construis ma propre classe ResolverServices. La vie est belle

Ce que je ne peux pas comprendre, c’est que le framework soit automatiquement injecté dans les classes non contrôleurs. Ce qui fonctionne, c’est que la structure s’injecte automatiquement dans les IOptions mon contrôleur, ce qui correspond effectivement à la configuration de mon projet:

 public class MessageCenterController : Controller { private readonly MyOptions _options; public MessageCenterController(IOptions options) { _options = options.Value; } } 

Je pense que je peux avoir la même chose pour mes propres cours et je suppose que je suis proche quand je mime le contrôleur, comme ceci:

 public class MyHelper { private readonly ProfileOptions _options; public MyHelper(IOptions options) { _options = options.Value; } public bool CheckIt() { return _options.SomeBoolValue; } } 

Je pense que j’échoue lorsque je l’appelle comme ceci:

 public void DoSomething() { var helper = new MyHelper(??????); if (helper.CheckIt()) { // Do Something } } 

Le problème que j’ai rencontré est pratiquement tout ce qui parle de DI en parle au niveau du contrôleur. J’ai essayé de rechercher où cela se passe dans le code source de l’object Controller , mais cela devient un peu fou.

Je sais que je peux créer manuellement une instance d’IOptions et la transmettre au constructeur MyHelper , mais il me semble que je devrais pouvoir obtenir le cadre, car il fonctionne pour les Controllers .

Votre aide est appréciée.

Vous trouverez ci-dessous un exemple d’utilisation de DI sans aucun élément impliquant des contrôleurs MVC. C’est ce que je devais faire pour comprendre le processus, alors peut-être que cela pourrait aider quelqu’un d’autre.

L’object ShoppingCart obtient, via DI, une instance d’INotifier (qui informe le client de sa commande.)

 using Microsoft.Extensions.DependencyInjection; using System; namespace DiSample { // STEP 1: Define an interface. ///  /// Defines how a user is notified. ///  public interface INotifier { void Send(ssortingng from, ssortingng to, ssortingng subject, ssortingng body); } // STEP 2: Implement the interface ///  /// Implementation of INotifier that notifies users by email. ///  public class EmailNotifier : INotifier { public void Send(ssortingng from, ssortingng to, ssortingng subject, ssortingng body) { // TODO: Connect to something that will send an email. } } // STEP 3: Create a class that requires an implementation of the interface. public class ShoppingCart { INotifier _notifier; public ShoppingCart(INotifier notifier) { _notifier = notifier; } public void PlaceOrder(ssortingng customerEmail, ssortingng orderInfo) { _notifier.Send("[email protected]", customerEmail, $"Order Placed", $"Thank you for your order of {orderInfo}"); } } public class Program { // STEP 4: Create console app to setup DI static void Main(ssortingng[] args) { // create service collection var serviceCollection = new ServiceCollection(); // ConfigureServices(serviceCollection) serviceCollection.AddTransient(); // create service provider var serviceProvider = serviceCollection.BuildServiceProvider(); // This is where DI magic happens: var myCart = ActivatorUtilities.CreateInstance(serviceProvider); myCart.PlaceOrder("[email protected]", "2 Widgets"); System.Console.Write("Press any key to end."); System.Console.ReadLine(); } } } 

Disons que MyHelper est utilisé par MyService qui à son tour est utilisé par votre contrôleur.

La façon de résoudre cette situation est la suivante:

  • Enregistrez MyService et MyHelper dans Startup.ConfigureServices .

     services.AddTransient(); services.AddTransient(); 
  • Le contrôleur reçoit une instance de MyService dans son constructeur.

     public HomeController(MyService service) { ... } 
  • MyService constructeur MyService recevra à son tour une instance de MyHelper .

     public MyService(MyHelper helper) { ... } 

Le framework DI pourra résoudre le graphe d’object entier sans problèmes. Si vous craignez que de nouvelles instances ne soient créées chaque fois qu’un object est résolu, vous pouvez en savoir plus sur les différentes options de durée de vie et d’enregistrement, telles que le singleton ou la durée de vie de la requête.

Vous devriez être vraiment méfiant lorsque vous pensez que vous devez créer manuellement une instance d’un service, car vous risquez de vous retrouver dans l’ anti-pattern de localisateur de services . Mieux vaut laisser les objects créer dans le conteneur DI. Si vous vous trouvez vraiment dans cette situation (supposons que vous créez une fabrique abstraite), vous pouvez utiliser directement IServiceProvider (demandez un IServiceProvider dans votre constructeur ou utilisez celui exposé dans httpContext ).

 var foo = serviceProvider.GetRequiredService(); 

Je recommanderais de lire la documentation spécifique sur le framework ASP.Net 5 DI et sur l’dependency injection en général.

Malheureusement, il n’y a pas de moyen direct. Le seul moyen de réussir à le faire fonctionner est de créer une classe statique et de l’utiliser partout ailleurs comme ci-dessous:

 public static class SiteUtils { public static ssortingng AppName { get; set; } public static ssortingng strConnection { get; set; } } 

Ensuite, dans votre classe de démarrage, remplissez-le comme suit:

 public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { //normal as detauls , removed for space // set my variables all over the site SiteUtils.strConnection = Configuration.GetConnectionSsortingng("DefaultConnection"); SiteUtils.AppName = Configuration.GetValue("AppName"); } 

Bien que ce soit un mauvais schéma, cela restra pendant tout le cycle de vie de l’application et je ne pouvais pas trouver un meilleur moyen de l’utiliser en dehors du contrôleur.