[AOP] L’interception avec Unity
Unity est un container IoC très pratique mais qui offre, en plus, la possibilité de réaliser un peu d’AOP (Aspect Oriented Programming) au moyen d’une extension pour l’interception.
En gros, vous allez avoir la possibilité d’intercepter l’exécution de bouts de code (appels de méthodes virtuelles, appels de méthodes définies dans des interfaces, etc.) pour rajouter votre propre logique.
Cela peut s’avérer très pratique lorsque vous avez, par exemple, des objets métiers ou des services mais pour lesquels vous ne souhaitez qu’ils s’occupent de gérer des tâches comme la gestion de logs, la gestion des exceptions, du cache, etc.
Voyons cela avec un exemple simple: imaginer que vous vouliez être en mesure de logger le temps d’exécution des méthodes que vous avez défini dans vos Client Services ou dans vos Helpers. Pour cela, il est d’abord nécessaire de créer la classe correspondante:
1: public interface ILogger
2: {
3: void Log(string errorMessage);
4: }
5:
6: public class Logger : ILogger
7: {
8: public void Log(string errorMessage)
9: {
10: // TODO: Implement method
11: }
12: }
A présent, nous allons ajouter les références nécessaire à notre projet pour pouvoir utiliser Unity et l’interception, à savoir Microsoft.Practices.Unity et Microsoft.Practices.Unity.Interception. Ensuite, nous allons pouvoir écrire notre CallHandler, il s’agit de la classe qui va pouvoir nous permettre de rajouter notre propre comportement:
1: public class LogExecutionTimeCallHandler : ICallHandler
2: {
3: public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
4: {
5: var sw = new Stopwatch();
6: sw.Start();
7:
8: IMethodReturn result = getNext()(input, getNext);
9:
10: sw.Stop();
11:
12: Debug.WriteLine("Method {0} tooks {1}",
13: input.MethodBase.Name,
14: string.Concat(sw.Elapsed.Hours, ":", sw.Elapsed.Minutes, ":",
15: sw.Elapsed.Seconds, ".", sw.Elapsed.Milliseconds));
16:
17: return result;
18: }
19:
20: public int Order { get; set; }
21: }
Comme vous pouvez le voir, cette classe se contente de démarrer un chronomètre, appelle la méthode qui est demandée puis affiche le temps d’exécution dans la fenêtre de déboggage de Visual Studio.
Cette classe est donc celle que nous devons utilisé mais nous ne pouvons pas le faire tel quel, nous allons essayer de nous simplifier la vie au maximum, en utilisant un attribut. Dès que cet attribut sera rencontré, il utilisera une instance de notre CallHandler et notre logique de log sera appelée:
1: public class LogExecutionTimeAttribute : HandlerAttribute
2: {
3: public override ICallHandler CreateHandler(Microsoft.Practices.Unity.IUnityContainer container)
4: {
5: return new LogExecutionTimeCallHandler();
6: }
7: }
Maintenant, il ne nous reste plus qu’à appliquer notre attribut sur chacune de nos méthodes, définies dans notre interface:
1: public interface ILogger
2: {
3: [LogExecutionTime]
4: void Log(string errorMessage);
5: }
Dès lors, nous pouvons mettre en place notre container Unity et configurer l’interception:
1: IUnityContainer container = new UnityContainer();
2: container.AddNewExtension<Interception>();
3: container.RegisterType<ILogger, Logger>().Configure<Interception>().
4: SetInterceptorFor<ILogger>(new InterfaceInterceptor());
5:
6: ILogger logger = container.Resolve<ILogger>();
7: logger.Log("TEST");
Nous pouvons voir ici que nous utilisons un InterfaceInterceptor, afin d’indiquer à Unity que les méthodes que nous voulons intercepter sont présentes dans l’interface que j’ai spécifié (ILogger). Si nous n’avions pas utilisé d’interface pour notre helper, nous aurions pû mettre en place des méthodes virtuelles, et utiliser un VirtualMethodInterceptor.
Lors de l’exécution, la méthode Log est correctement appelé et notre chronomètre est, lui aussi, bien démarré et utilisé:

Il s’agit donc là d’une technique très pratique lorsque l’on souhaite mettre en oeuvre du log, du cache, etc. et que l’on ne désire pas implémenter ces fonctionnalités directement sur ces objets !
Plus d’informations: http://www.palmmedia.de/Blog/2010/9/26/aop-interception-with-unity-2.0
A+,
Ce post vous a plu ? Ajoutez le dans vos favoris pour ne pas perdre de temps à le retrouver le jour où vous en aurez besoin :