Ayant récemment intensifié l'utilisation de 6 d'entre eux ( Windsor , Unité , Spring.Net , Autofac , Ninject , StructureMap ) Je peux vous proposer un résumé rapide de chacun, de nos critères de sélection et de notre choix final.
Remarque : nous n'avons pas examiné PicoContainer.Net car l'un des membres de notre équipe a estimé que le portage .Net était très médiocre par rapport à la version Java. Nous n'avons pas non plus examiné ObjectBuilder, car Unity est construit sur ObjectBuilder2 et est considéré comme un choix supérieur par défaut.
Tout d'abord, je peux dire qu'ils sont tous plus ou moins similaires et qu'il s'agit de trouver ce qui vous convient le mieux, en fonction de vos besoins spécifiques. Nos besoins étaient les suivants
Exigences
- Injection basée sur le constructeur (nous avons l'intention de pas pour utiliser l'injection de propriétés, de champs ou de méthodes)
- Configuration programmable ( pas XML)
- les hiérarchies de conteneurs (une par application, par demande et par session pour lier plus implicitement la portée de la durée de vie des composants au conteneur)
- gestion de la durée de vie des composants (pour un découpage plus granulaire, par exemple transitoire / singleton)
- injection de l'interface vers le type ou l'instance concrète (ex.
ILogger -> typeof(FileLogger)
ou ILogger -> new FileLogger()
)
- création avancée de composants / "mécanisme événementiel creaton" pour la pré/post initialisation
- l'élimination correcte de
IDisposable
composants sur le démontage du conteneur
-
bien documenté et/ou informations en ligne facilement disponibles
Remarque : bien que la performance soit une exigence, elle n'a pas été prise en compte dans la sélection, car il semble que tous les conteneurs examinés étaient similaires à cet égard. repère
Test
Chaque conteneur a été utilisé dans un projet Asp.Net webforms typique (puisque c'était notre type d'application cible). Nous avons utilisé une page simple et un contrôle utilisateur simple, chacun héritant respectivement d'une page de base et d'un contrôle de base. Nous avons utilisé un conteneur sur la page BasePage
pour un conteneur de portée "per request" et 1 sur le global.asax pour une portée "application" et a tenté de les enchaîner afin que les dépendances puissent être résolues à partir des deux conteneurs.
Chaque application web partageait un ensemble artificiel d'objets de domaine simulant plusieurs niveaux de dépendance, le type de portée (singleton/transitoire) et également des classes gérées et non gérées ( IDisposable
nécessaire). Les composants de dépendance de "niveau supérieur" ont été injectés manuellement à partir des méthodes de l'objet BasePage
.
Résultats
Windsor - A satisfait à tous les critères et dispose d'un bon historique de cas, d'une communauté de blogueurs et d'une documentation en ligne. Facile à utiliser et probablement le choix de facto. Création avancée de composants grâce à la fonction Factory. Permet également de chaîner des conteneurs créés individuellement.
Spring.Net - Documentation verbeuse et peu utile et configuration non évidente / facile à programmer. Ne supporte pas les génériques. Pas choisi
Ninject - Facile à utiliser avec une bonne documentation claire. Fonctionnalités puissantes répondant à toutes nos exigences, à l'exception des hiérarchies de conteneurs, qui n'ont malheureusement pas été retenues.
StructureMap - Peu documenté, bien que disposant d'un ensemble de fonctionnalités avancées qui répondaient à toutes nos exigences, il n'y avait pas de mécanisme intégré pour les hiérarchies de conteneurs, bien qu'il ait pu être bricolé à l'aide de boucles for voir ici L'interface fluide de l'expression lambda semblait un peu trop compliquée au début, mais elle pouvait être encapsulée.
Unity - Bien documenté, facile à utiliser et répondant à tous nos critères de sélection, il dispose d'un mécanisme d'extension facile à mettre en place pour ajouter le mécanisme d'événement pré/post création dont nous avions besoin. Les conteneurs enfants devaient être créés à partir d'un conteneur parent.
Autofac - Bien documenté et relativement facile à utiliser, bien que la configuration des expressions lambda semble un peu trop compliquée, mais, là encore, elle peut être facilement encapsulée. La définition de la portée des composants est réalisée par un mécanisme de "marquage" et tous les composants sont configurés en amont à l'aide d'un constructeur, ce qui n'est pas très pratique. Les conteneurs enfants sont créés à partir d'un parent et se voient attribuer des composants à partir d'un "tag". Injection générique autorisée.
Conclusion
Notre choix final s'est porté sur Windsor et Unity, et cette fois-ci, nous avons choisi Unity en raison de sa facilité d'utilisation, de sa documentation, de son système d'extension et de son statut de "production".