Recherchez la racine de composition appropriée pour une bibliothèque .NET

J’ai lu diverses autres questions ici sur l’argument, notamment

Bibliothèque conviviale «Dependency Inject (DI)»

Ioc / DI – Pourquoi dois-je référencer tous les calques / assemblages dans l’application d’entrée?

et cet article (et autre matériel divers).

Cependant, il m’est difficile de savoir où placer la composition dans un projet .NET bibliothèque (DLL). Le projet n’appartient à aucun type spécifique mentionné dans l’article. Sur le bureau, la console ou même les applications Web, ce point est clairement défini.

Mon approche actuelle consiste à envelopper le conteneur, à enregistrer les types et à réexposer la méthode Resolve:

class DefaultBootstrapper : IBootstrapper { public Bootstrapper() { _container = new XXXContainer(); RegisterTypes(_container); } public T Resolve() where T : class { return _container.Resolve(); } // + other _container.Resolve() overloads private readonly XXXContainer _container; } 

Ensuite, j’empêche les utilisateurs de bibliothèque de créer des instances racine de la bibliothèque (par exemple, en définissant des constructeurs internes), ce qui oblige à utiliser une fabrique de singleton:

 class XYZFactory { static XYZFactory() {} private XYZFactory(IBootstrapper bootstrapper) { _bootstrapper = bootstrapper; } public static XYZFactory Instance { get { return Singleton; } } public ABCType CreateABCType(ssortingng param1) { return _bootstrapper.Resolve(param1, _bootstrapper.Resolve); } private static readonly XYZFactory Singleton = XYZFactory(new DefaultBootstrapper); private readonly IBootstrapper _bootstrapper; } 

La question est la suivante: existe-t-il une meilleure approche ou un meilleur modèle à utiliser pour localiser la racine de la composition dans un projet de bibliothèque?

Cela dépend du type de bibliothèque que vous créez. Votre projet de bibliothèque fait-il partie de votre propre solution ou s’agit-il d’une bibliothèque réutilisable dont dépendent d’autres développeurs, en dehors de votre équipe, de votre service ou peut-être même de votre organisation?

S’il ne s’agit que d’un projet de bibliothèque faisant partie d’une solution, le projet de bibliothèque ne doit généralement pas contenir de racine de composition. Par définition, la racine de la composition est un “emplacement (de préférence) unique dans une application où les modules sont composés ensemble”. En d’autres termes, votre solution comporterait un ou plusieurs projets de démarrage (telle qu’une application MVC, un service WCF, une application de console) et chaque projet de démarrage disposerait de sa propre racine de composition. Les couches ci-dessous n’auraient pas leur propre racine de composition.

Cela ne signifie pas pour autant que vous ne devriez pas empêcher la duplication de code dans les racines de la composition. Lorsqu’il y a beaucoup de duplications causées par un câblage par défaut pour les projets inclus (tels que DAL et BLL), vous devez généralement extraire cette logique vers un autre projet. Vous pouvez le faire en incluant une partie de la logique d’enregistrement dans l’un des projets (le plus probablement le BLL) et en laissant chaque racine de la composition appeler cette logique partagée, ou en ajoutant un projet spécial “bootstrapper” pour ce projet et les projets référencés. Ce projet d’amorçage ne contiendra que la logique d’enregistrement. En séparant cette logique des assemblys d’application, vous évitez que ces assemblages nécessitent une dépendance à la bibliothèque d’dependency injections utilisée. Toutefois, il n’est généralement pas problématique si un assembly prend une dépendance sur cette bibliothèque, tant que vous vous assurez que la logique de l’application rest exempte de dépendances sur le conteneur.

Pour les bibliothèques réutilisables, les choses sont généralement différentes. Dans ce cas, les utilisateurs utiliseront votre bibliothèque, mais vous n’avez aucun contrôle sur la manière dont ils structurent leur application. Vous souhaitez souvent fournir la bibliothèque de manière à ce qu’elle puisse être directement consommée par les consommateurs, sans avoir à effectuer toutes sortes d’enregistrements «complexes» dans leur racine de composition. Souvent, vous ne savez même pas s’ils ont une racine de composition.

Dans ce cas, vous devriez généralement faire fonctionner votre bibliothèque sans conteneur DI. Vous ne devriez pas vous-même prendre une dépendance sur un tel conteneur, car cela entraînerait le conteneur. Si vous utilisez un conteneur, demandez-vous pourquoi votre bibliothèque réutilisable utilise un conteneur et si cela doit être le cas. Peut-être que vous le faites parce que vous avez conçu tous les types autour du principe d’dependency injection; parce que cela facilite les tests. N’oubliez pas que c’est votre problème, pas le problème de vos consommateurs. En tant que concepteur de bibliothèque réutilisable, vous devez vous efforcer de rendre votre bibliothèque aussi utilisable que possible pour vos consommateurs. Ne supposez jamais que vos consommateurs utilisent un conteneur DI. Même s’ils pratiquent l’dependency injection, ils peuvent appliquer Pure DI plutôt qu’un conteneur DI.

Si vous construisez une bibliothèque réutilisable, jetez un coup d’œil à cet article de Mark Seemann sur le blog .