Unity est un composant issu des Patterns & Practices de Microsoft, ce containeur d’injection de dépendance est léger et extensible. Il facilite aisément la construction d’applications modulaires faiblement couplées. Bref, c’est un framework Ioc !
Cependant, avant cela, j’ai beaucoup utilisé autofac et je me suis retrouvé avec certains manques, comme par exemple la création de modules.
Les modules autofac sont des classes extrêmement basiques qui permettent de simplifier la configuration des containeurs de votre projet.
Il y a bien sûr plusieurs façon de procéder :
- Créer un module par cible (MVC, WebApi, WP8.1, Windows 10, tests unitaires…) ;
- Créer un module par assembly ;
- Créer un module par environnement (Prod, Dev…)
Il y a maintes façons de se servir des modules !
Malheureusement, dans Unity, point de module ! On peut s’y retrouver autrement bien sûr, mais je souhaitais retrouver cette souplesse.
Voici donc comment j’ai ajouté des modules à Unity : (ça me fait penser que je peux proposer cette fonctionnalité via github)
Pour commencer, on va définir notre classe abstract UnityModule comme ceci :
using Microsoft.Practices.Unity; namespace Microsoft.Practices.Unity { /// <summary> /// Module to easily configure type mapping /// </summary> public abstract class UnityModule { /// <summary> /// Register types /// </summary> /// <param name="container"></param> public abstract void Register(IUnityContainer container); } }
Puis quelques extensions pratiques :
using Microsoft.Practices.Unity; namespace Microsoft.Practices.Unity { public static class UnityContainerExtensions { /// <summary> /// Register module in the container /// </summary> /// <param name="container"></param> /// <param name="module"></param> /// <returns></returns> public static IUnityContainer RegisterModule( this IUnityContainer container, UnityModule module) { module.Register(container); return container; } } }
namespace Microsoft.Practices.Unity { public static class UnityExtensions { public static T GetService<T>(this IDependencyResolver resolver) where T : class { return resolver.GetService(typeof (T)) as T; } public static IEnumerable<T> GetServices<T>(this IDependencyResolver resolver) where T : class { return resolver.GetServices(typeof (T)) as IEnumerable<T>; } } }
Les extensions GetService et GetService ne sont pas essentielles mais sont pratiques à l’usage.
Usage
A l’usage, c’est très simple, pour déclarer un module, il suffit d’implémenter la classe abstraite UnityModule comme ceci :
public class DevModule : UnityModule { public override Register(IUnityContainer container) { container.RegisterType<ICustomerRepository, MongoDbCustomersRepository>(); container.RegisterType<ISalesRepository, MongoDbSalesRepository>(); container.RegisterType<IRestHttpClient, DevRestHttpClient>(); } }
Puis, dans votre projet principal :
IUnityContainer container = new UnityContainer(); ... container.RegisterModule(new DevModule()); ...
Tout simplement !
Finalement, j’aime beaucoup créer un module par assembly, comme ça au démarrage de l’application, je me contente de scanner les types de l’AppDomain et d’importer automatiquement ceux qui implémentent UnityModule.