Bienvenue à Blogs CodeS-SourceS Identification | Inscription | Aide

Thomas Lebrun

Tout sur WPF, LINQ, C# et .NET en général !

Actualités

[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é:

image

 

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 :
Posted: jeudi 4 août 2011 15:54 par Thomas LEBRUN
Classé sous : , , ,

Commentaires

tomlev a dit :

Sympa ! Par contre, un petit détail qui me chiffonne :

  6:         sw.Start();

  7:  

  8:         IMethodReturn result = getNext()(input, getNext);

  9:  

 10:         sw.Stop();

Avec ça le Stopwatch mesure aussi le temps d'exécution de getNext ; il faudrait appeler getNext avant de démarrer le Stopwatch, sinon le résultat est faussé...

# août 4, 2011 16:34

Thomas LEBRUN a dit :

Yep, en effet mais c'était surtout pour donner une idée de ce que l'on peut faire :)

Mais bonne remarque, merci !

# août 4, 2011 16:50

grogru a dit :

C'est cool ce truc ! :-)

# août 5, 2011 10:03
Les commentaires anonymes sont désactivés

Les 10 derniers blogs postés

- Intégration Yammer et SharePoint Online (Office 365), étape 1 … par Le blog de Patrick [MVP SharePoint] le 06-12-2013, 17:37

- [Dynamics CRM] Ajouter les dossiers de CRM au dossier Favoris d’Outlook par Christine Dubois le 06-10-2013, 15:50

- Visual Studio 2013 par Etienne Margraff le 06-04-2013, 10:26

- Configurer la collation SQL Server pour SharePoint par Blog de Jérémy Jeanson le 06-03-2013, 19:48

- Etendre le Team Web Access de TFS 2012 – Step 1: Création du plugin par Philippe Didiergeorges Aka Philess le 06-03-2013, 07:30

- Livre Blanc : Développer des applications NUI par Fathi Bellahcene le 06-01-2013, 11:35

- [Dynamics CRM 2011] Copier une vue d'entité par Christine Dubois le 05-29-2013, 13:20

- [Conf’SharePoint 2013] Mes présentations… par Le blog de Patrick [MVP SharePoint] le 05-28-2013, 09:04

- [wpdev] Storage bug in MediaLibrary.SavePicture par Kévin Gosse le 05-26-2013, 19:08

- VMMap en mode instrumentation sur système 64bit : attention à la plateforme cible du build .NET par CoqBlog le 05-25-2013, 22:25