paint-brush
Besoin de connaître les conseils pour Autofac ContainerBuilder dans ASP.NET Corepar@devleader
760 lectures
760 lectures

Besoin de connaître les conseils pour Autofac ContainerBuilder dans ASP.NET Core

par Dev Leader12m2024/05/10
Read on Terminal Reader

Trop long; Pour lire

Découvrez comment utiliser Autofac ContainerBuilder dans ASP.NET Core pour câbler l’injection de dépendances. Je vais explorer ce que nous pouvons et ne pouvons pas faire avec cette approche !
featured image - Besoin de connaître les conseils pour Autofac ContainerBuilder dans ASP.NET Core
Dev Leader HackerNoon profile picture
0-item


Il existe de nombreuses façons de gérer l'injection de dépendances dans nos applications, et je pense qu'il est important de comprendre les avantages et les limites des différentes approches. Utiliser un Autofac ContainerBuilder dans ASP.NET Core comme principal moyen de structurer vos dépendances au lieu d'utiliser l' AutofacServiceProviderFactory suggéré est l'une de ces voies que nous pouvons explorer !


Dans cet article, je souligne comment utiliser ContainerBuilder d'Autofac dans votre application ASP.NET Core au lieu d'AutofacServiceProviderFactory. Nous examinerons ce que vous pouvez et ne pouvez pas faire avec cette approche par rapport aux autres approches auxquelles nous avons accès avec l'injection de dépendances.


Cela fera partie d'une série dans laquelle j'explore la résolution des dépendances avec Autofac dans ASP.NET Core. Je ne manquerai pas d'inclure la série ci-dessous au fur et à mesure que les numéros seront publiés :


À la fin de cette série, vous serez en mesure d'explorer avec plus de confiance les architectures de plugins dans ASP.NET Core et Blazor, ce qui vous fournira encore plus de contenu à explorer.


Le problème avec AutofacServiceProviderFactory

Pour être honnête, le titre de la section est *presque* un appât à clics. Je pense que l'utilisation AutofacServiceProviderFactory comme moyen suggéré pour configurer Autofac dans vos applications ASP.NET Core est idéale pour la plupart des applications. La grande majorité des développeurs qui souhaitent utiliser Autofac comme cadre d'injection de dépendances de choix ne rencontreraient pas beaucoup de problèmes de cette façon.


Cela nous offre la possibilité de :

  • Accédez à WebApplicationBuilder (et à tout ce qui est disponible à ce stade)
  • Accès à l'instance de IConfiguration (également disponible hors de l'instance WebApplicationBuilder )
  • Possibilité de transmettre les dépendances sur un minimum d'API


Mais le gros problème pour moi : nous ne pouvons pas accéder à l'instance WebApplication . Lorsque je crée des architectures de plugins en C#, en particulier lors de la création d'applications ASP.NET Core, j'aime avoir accès à l'instance WebApplication afin d'enregistrer des routes. Cela me permet d'enregistrer facilement un minimum d'API de mes plugins, qui techniquement n'ont besoin que d'accéder à une implémentation de IEndpointRouteBuilder pour obtenir la syntaxe pratique.

Puis-je enregistrer des API non minimales sans cela ? Absolument. Existe-t-il un autre moyen de fournir une syntaxe similaire et de ne pas nécessiter d'instance WebApplication ? Très probable. Mais au lieu d'essayer de contourner CE problème, je voulais voir si je pouvais simplement accéder à la dépendance qui m'intéresse.


Il était temps de changer le plan de configuration de mon conteneur de dépendances !


Explorer un exemple d'application ASP.NET Core

Examinons un exemple d'application afin d'avoir un terrain d'entente à explorer. Si vous avez lu l'article précédent , cela ressemblera à une variante de l'exemple d'application météo :

 using Autofac; using Microsoft.AspNetCore.Mvc; // personal opinion: // I absolutely love having the entry point of my // applications being essentially: // - make my dependencies // - give me the primary dependency // - use it // - ... nothing else :) ContainerBuilder containerBuilder = new(); containerBuilder.RegisterModule<MyModule>(); using var container = containerBuilder.Build(); using var scope = container.BeginLifetimeScope(); var app = scope.Resolve<WebApplication>(); app.Run(); internal record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary) { public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); } internal sealed class MyModule : Module { protected override void Load(ContainerBuilder containerBuilder) { containerBuilder.RegisterType<DependencyA>().SingleInstance(); containerBuilder.RegisterType<DependencyB>().SingleInstance(); containerBuilder.RegisterType<DependencyC>().SingleInstance(); containerBuilder .Register(ctx => { var builder = WebApplication.CreateBuilder(Environment.GetCommandLineArgs()); return builder; }) .SingleInstance(); containerBuilder .Register(ctx => ctx.Resolve<WebApplicationBuilder>().Configuration) .As<IConfiguration>() .SingleInstance(); containerBuilder .Register(ctx => { var builder = ctx.Resolve<WebApplicationBuilder>(); var app = builder.Build(); app.UseHttpsRedirection(); // FIXME: the problem is that the Autofac ContainerBuilder // was used to put all of these pieces together, // but we never told the web stack to use Autofac as the // service provider. // this means that the minimal API will never be able to // find services off the container. we would need to resolve // them BEFORE the API is called, like in this registration // method itself, from the context that is passed in. //DependencyA dependencyA = ctx.Resolve<DependencyA>(); // FIXME: But... What happens if something wants to take a // dependency on the WebApplication instance itself? Once the // web application has been built, there's no more adding // dependencies to it! var summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" }; app.MapGet( "/weatherforecast", ( [FromServices] DependencyA dependencyA , [FromServices] DependencyB dependencyB , [FromServices] DependencyC dependencyC ) => { var forecast = Enumerable .Range(1, 5) .Select(index => new WeatherForecast ( DateOnly.FromDateTime(DateTime.Now.AddDays(index)), Random.Shared.Next(-20, 55), summaries[Random.Shared.Next(summaries.Length)] )) .ToArray(); return forecast; }); return app; }) .SingleInstance(); } } internal sealed class DependencyA( WebApplicationBuilder _webApplicationBuilder); internal sealed class DependencyB( WebApplication _webApplication); internal sealed class DependencyC( IConfiguration _configuration);


L'un des points forts de cette approche est que l'utilisation de la classe Autofac ContainerBuilder comme conteneur de dépendances principal nous offre la possibilité de structurer notre point d'entrée simplement :

  • Création de conteneur
  • Enregistrement des dépendances
  • Résolution des dépendances primaires
  • … Appelez une seule méthode pour démarrer l’application !


C'est, à mon avis, le code de démarrage d'application idéal. Pourquoi? Parce que vous n’avez jamais besoin de revenir ici pour y toucher. Jamais. Peu importe le nombre de choses que vous ajoutez ! Et c'est tout parce que vous pouvez numériser des assemblys pour charger plus de modules.

Encore une fois, c'est une de mes préférences personnelles, et je n'essaie pas de prétendre que cela devrait être l'objectif de tout le monde.

Les défauts d'Autofac ContainerBuilder dans ASP.NET Core

Bien sûr, il s’agit d’une autre approche qui n’est pas tout à fait à l’épreuve des balles. Discutons donc de ce que nous n'obtenons PAS avec cette configuration d'Autofac :

  • Les paramètres résolus par le service transmis sur des API minimales ne fonctionnent tout simplement pas. L' WebApplication qui a été construite n'est pas configurée pour utiliser Autofac comme framework d'injection de dépendances !
  • Comme dans l'article précédent, nous ne parvenons toujours pas à obtenir l'instance WebApplication sur le conteneur de dépendances… Nous n'avons donc fait aucune avancée spécifique pour y accéder.


Mais c'est surtout ça ! Ce n'est pas une liste terrible d'inconvénients, mais l'approche Autofac ContainerBuilder n'était pas une solution miracle pour nous. Alors, qu’en avons-nous retiré ? aidera également à expliquer les éléments suivants :

Les avantages d'Autofac ContainerBuilder dans ASP.NET Core

Avantages et inconvénients de tout ce que nous faisons ! Maintenant que nous avons vu les problèmes liés à Autofac ContainerBuilder dans ASP.NET Core, il est temps d'examiner les avancées que nous en avons retirées :


  • Nous pouvons toujours accéder aux instances WebApplicationBuilder et IConfiguration , c'est donc un avantage comparable à l'utilisation de l'approche AutofacServiceProviderFactory .
  • Nous pouvons obtenir un point d’entrée très simplifié à notre programme, ce que j’aime vraiment voir. Création de conteneur, enregistrement, résolution de votre méthode de point d'entrée, et c'est tout !
  • Les API minimales fonctionnent, mais pas avec les dépendances. Néanmoins, nous pouvons pré-résoudre les dépendances souhaitées par les API minimales et les transmettre au moment de l'enregistrement de la méthode. Voir le code commenté !

Plus d'inversion pour les routes ASP.NET basées sur des plugins ?

Nous avons vu que nous pouvions enregistrer des API minimales au sein d'une méthode d'enregistrement Autofac, mais malheureusement, nous ne pouvons pas résoudre les dépendances du conteneur directement sur l'appel d'API minimal lui-même. Nous pourrions créer une classe dédiée comme la suivante qui gère les définitions de routes avec des dépendances résolues automatiquement :

 internal sealed class WeatherForecastRoutes( DependencyA _dependencyA // FIXME: still can't depend on this because // we can't get the WebApplication //, DependencyB _dependencyB , DependencyC _dependencyC) { private static readonly string[] _summaries = new[] { "Freezing", "Bracing", // ... }; public WeatherForecast[] Forecast() { var forecast = Enumerable.Range(1, 5).Select(index => new WeatherForecast ( DateOnly.FromDateTime(DateTime.Now.AddDays(index)), Random.Shared.Next(-20, 55), _summaries[Random.Shared.Next(_summaries.Length)] )) .ToArray(); return forecast; } }


La résolution automatique se produit si nous avons cette classe ET les dépendances sur le même conteneur. Il suffit ensuite d'appeler ce code :

 var weatherForecastRoutes = ctx.Resolve<WeatherForecastRoutes>(); app.MapGet("/weatherforecast2", weatherForecastRoutes.Forecast);


Cela craint encore un peu du point de vue du plugin, car nous aurions besoin de résoudre manuellement toutes les classes de route juste pour appeler le code d'enregistrement comme ça - tout cela provenant du fait que ces choses ne peuvent pas résoudre leur propre accès à l' WebApplication exemple.


Mais attendez… Et si nous retournions les choses ? Et si nous pouvions résoudre une interface comme IRegisterRoutes et transmettre l'instance WebApplication ?!

 // NOTE: make sure to register WeatherForecastRouteRegistrar on the // autofac container as IRegisterRoutes! internal interface IRegisterRoutes { void RegisterRoutes(WebApplication app); } internal sealed class WeatherForecastRouteRegistrar( WeatherForecastRoutes _weatherForecastRoutes) : IRegisterRoutes { public void RegisterRoutes(WebApplication app) { app.MapGet("/weatherforecast2", _weatherForecastRoutes.Forecast); } } // TODO: add this to the autofac code where the // WebApplication instance is built: foreach (var registrar in ctx.Resolve<IEnumerable<IRegisterRoutes>>()) { registrar.RegisterRoutes(app); }


Désormais, nous n'avons même plus besoin de nous soucier de savoir si l'instance WebApplication est accessible à nos plugins ! Peut-être que la première version n'était pas si restrictive après tout. Peut-être que nous sommes sur quelque chose ici… Cependant, le prochain article devrait expliquer cela plus en détail.


Conclusion d'Autofac ContainerBuilder dans ASP.NET Core

Dans cet article, j'ai exploré l'utilisation explicite d'un Autofac ContainerBuilder au lieu d'utiliser AutofacServiceProviderFactory comme cela est normalement suggéré. Nous avons constaté des avantages et des inconvénients similaires, mais également un ensemble différent de facteurs à prendre en compte. Chaque méthode peut présenter des avantages et des inconvénients en fonction de ce que vous recherchez dans votre candidature.


Ce qui était intéressant, c'est que si nous essayons de travailler sur des plugins, nous n'aurons peut-être même pas besoin d'accéder à l'instance WebApplication à partir de nos plugins ! Si l’on se soucie d’API minimales, cela peut quand même être limitant… mais sinon, nous sommes dans une réflexion intéressante !

Si vous avez trouvé cela utile et que vous recherchez davantage d'opportunités d'apprentissage, pensez à vous abonner à ma newsletter hebdomadaire gratuite sur le génie logiciel et regardez mes vidéos gratuites sur YouTube !