martes, enero 22, 2008

Aspect Oriented Programming Aplicado - PostSharp, Logging y HttpSimulator

Siempre me había intrigado por AOP y es que la idea de programar basado en aspectos en lugar de funciones o metodos o código secuencial es bastante atractiva. Obviamente no es para todo código, pero hay muchos "aspectos" que quisieramos poder tener encapsuladas y no sólo en un objeto, sino, despreocuparnos y no tener que invocarlas nosotros mismos.

Ejemplo Simple - Logging.

Pensemos que queremos loggear excepciones.

image

Ok, ese el código feo de novato. Ahora refactoricemos un poco. Podría estar en una clase y para cuestiones de la prueba hagamosla estática.

image

Ahora apliquen eso a todos los metodos de la clase. ¿Qué? Bueno supongan que nos interese enterarnos en nuestro archivo de Log de todos los lugares donde lleguue a ocurrir una excepción. Vamos a convertir esto en un aspecto. Refactoricemos de nuevo.

image

Simplemente hicimos nuestra clase serializable (necesario por PostSharp), hereda de OnExceptionAspect, overrideamos el Metodo OnException y listo, Logueamos tal como antes.

image

Ahora simplemente decoramos nuesto metodo con nuestro nuevo atributo, corremos la app y listo. El atributo también podría ir en una clase y aplicarle algunos filtros. Estas son sólo algunas de las posibilidades.

Puedes descargar el código aquí

Por mantener breve el ejemplo, la clase loggin es muy simple, en una aplicación real sugeriría usar el Loggin Application Block que es parte del Enterprise Library o Log4Net, ambos son open source y podrían integrarse con PostSharp.

Para un ejemplo aún más simple que este, vean el Video de Intro de PostSharp. El ejemplo me parecio poco práctico, sin embargo, es muy ilustrativo respecto a como usar la herramienta y sólo dura 5 minutos. Pueden bajar el código del video aquí.

Otro Ejemplo Simple - HttpSimulator

Hace algún tiempo escribi respecto al HttpSimulator, desde entonces lo hemos tenido que usar muchas veces para simular el contexto de Http en clases que dependen de algun objeto de ASP.NET y queremos probarla sin necesidad de que tenga dependencias a los objetos reales del framework, es decir, no queremos tener que usar realmente sesión y pasar por todo el pipeline de un request web, sólo para probar un simple metodo.

En el código a descargar viene todo el HttpContext, ahorita nos enfocaremos a las pruebas unitarias, estilo TDD para el HttpContext y como usarlo con PostSharp, en la prueba usaremos un WebDependentClass

image

Eso esperamos que arroje una excepcion, ya que WebDependentClass se debería ejecutar en un contexto web para que pueda usar HttpContext.Current tal como se muestra.

image

Ahora veamos como se haría esto con el HttpSimulator para lo que creamos otra prueba.

image

Es simple, se obtiene el path, se crea la instancia, se empieza a simular el request, se hace lo que se tenga que hacer y al salir del using se ejecuta el dispose y termina la simulación. Nuestra prueba pasa y todos contentos. Sólo que es mucha talacha. Puede haber 126 pruebas más que usen el Simulator. Aunque se podría simplificar un poco la creación, terminaríamos aún así con código repetido y el using no tenemos manera de evitarlo.

Con AOP, tenemos algo como lo siguiente:

image

El atributo se encarga de todo, inclusive si todas las pruebas de nuestro TestClass o nuestro Assembly de pruebas necesitaran del simulador podríamos definir el atributo a nivel de clase o assembly para aplicarles el mismo aspecto.

La implementación del atributo es de lo más simple. Tal como hicimos con el Logging, tenemos la clase serializable y hereda de un atributo predefinido en PostSharp.

image

Parece un Surround with snippet no? Es similar sólo que para tiempo de compilación.

Si quieres usarlo en tus pruebas, simplemente agrega el Assembly HttpSimulator y el atributo a las que dependan de un contexto Http. Puedes bajar el código de aquí.

Links

Downloads

SuperSimpleSample
LoggingSample
Attribute para el HttpContextSimulator
Todos los samples de este post
PostSharp Installer

PostSharp

PostSharp en .NET Rocks
PostSharp
Video de Intro de PostSharp

HttpSimulator

Post viejo mio
HttpSimulator

Miguel Madero

6 comentarios:

Diego Correa dijo...

Hola Miguel Madero, te saludo desde Paraguay, estoy investigando sobre AOP justamente porque estoy haciendo mi tesis (trabajo de grado) de mi carrera en base a esto, me gusto tu ejemplo de logging en C#, pero me gustaria saber si hay otros ejemplos mas ilustrativos como ser aspecto de sincronizacion, invocacion remota, etc, mejor siempre si es en c
# .net, muchas gracias, saludos desde Paraguay, por cierto me llamo Diego Correa

Miguel Madero dijo...

Francisco,

Que bueno que te te intereses en el tema, la tiene muchas oportunidades.
Te comento que he seguido desarrollando plugins (extensiones) usando PostSharp, estos son algunos de los ejemplos:
1. Automaticamente implementar INotifyPropertyChanged para poder utilizar Automatic Properties en todas las clases que implementen otro interfaz en particular.
2. Bloquear llamadas a metodos en base al rol del usuario en tiempo de ejecucion y opcionalmente mostrar un mensaje de error.
3. Agrear transacciones a un metodo.
4. Encapsular excepciones en ciertos metodos.

Hay algunos otros Aspectso que tengo en mente desarrollar, pero por falta de tiempo no he podido hacerlo.
1. Marcar una propiadad como dependendiente de otra, asi cuando una cambia, la clase notifica tambien que cambio la segunda. Esto es muy util en escenarios que dependen mucho de DataBinding como en WPF y Silverlight.
2. Deep Depends On. Similar a la anterior, pero incluyendo jerarquias de objetos. Por ejemplo una propiedad puede depender en propiedades de otros objetos (o propiedades de propiedades de propeiades en N niveles). Asi si cambia cualquiera de estos, lanzamos una notificacion de cambio por la primera.
3. Validaciones a nivel de propiedades e.g. algo no puede ser nulo o tiene que ser mayo que un cierto numero. Si no se cumple la validacion, se registra un error y notifica a los padres que el objeto se encuentra en un estado invalido. Lo que hace mas facil validar jerarquias de objetos, por ejemplo, si un producto no es valido en una orden, toda la orden es invalida.
Tambien trabaje en conjunto con el aspecto anterior para hacer propeidades dependientes iguamente invalidas.
Nos permite tambien validad en ambias vias. Es decir, si cambia el precio, debemos validad el total y el Tax.
4. Crear Dependency Properties a partir de Automatic Properties.


Algunas de estas estan muy casadas con un framework que usamos internamente, para manejar la seguridad y validaciones, pero podria mandarte algunos ejemplos.

Te sugiero ver los plugins en la pagina de PostSharp
http://www.postsharp.org/contributions

Tambien puedes checar el Injection Application Block de Patterns and Practices en CodePlex (es parte del Enterprise Application Blocks) y Dynamic Proxy que es parte de Castle Project.

Avisame como te va con la tesis.

Saludos

Anónimo dijo...

Buen dia Miguel,

He estado buscando un ejemplo de como implementar un "logger" con AOP.

Actualmente en mi proyecto yo utilizo el Log4Net, pero mi codigo se ve muy sucio, quisiera sacarlo y dejar toda la logica de "logging" en un solo lado.

Mi pregunta es, yo en mis metodos tengo varios niveles de "logging" por ejemplo, DEBUG, INFO, WARING, y EXCEPTION..

Como podria yo sacar esto utilizando PostSharp?

P.D: Si es posible que la respuesta a esta pregunta me sea notificada a the.email.trash@gmail.com te lo agradecere)
Saludes

Miguel Madero dijo...

spiralni,

Hay unas extensiones para PostSharp (log4PostSharp). Lo puedes descargar aqui:
http://code.google.com/p/postsharp-user-plugins/wiki/Log4PostSharp

Este articulo es una buena introduccion a AOP y Logging que hace referencia al mismo plugin
http://www.codeproject.com/KB/dotnet/log4postsharp-intro.aspx

Este un blog post del creadot the PostSharp que habla respecto al plugin
http://www.postsharp.org/blog/introducing-log4postsharp

Yo no lo he usado, pero se que es uno de los plugins y escenarios mas populares en PostSharp.

MsOtaru dijo...

Hola, saludos desde Perú. Me resulta bastante útil la informacion que has publicado. Más bien quisiera pedirte si pudieras subir de nuevo los ejemplos ya que no se pueden descargar.
Muchas Gracias

Miguel Madero dijo...

Hola MsOtaru,

Desafortunadamente los ejemplos fueron borrados del sitio donde los habia publicado y no he podido encontrar una copia :(
Lamento no poderte ayudar.

Por favor considera que estos ejemplos ya tienen mas de un anio. PostSharp libero una nueva version recientement y mucho ha cambiado (en especial que ya no es graits).

Te sugiero checar http://www.sharpcrafters.com/ tambien busca info en Mono.Cecil que es otra herramienta para hacer algo similar.

Saludos