Como han estado todos? Feliz año :D. En esta ocasión quiero compartirles un artículo pequeño sobre un escenario común en el desarrollo aplicaciones web de línea de negocio.
En este tipo de aplicaciones una gran cantidad de las operaciones o acciones que nuestro usuario realiza deben ser auditadas, unas con más detalle que otras, por lo que terminamos con controladores que suelen verse de esta forma.

Como pueden ver al recibir los datos del usuario y antes de persistirlos agregamos detalles de auditoria de forma manual, como el Id del usuario que está realizando la operación y probablemente la dirección Ip.

nueva.UserId = User.Identity.GetUserId();
nueva.Ip = HttpContext.Request.UserHostAddress;

Ahora bien, considerando una aplicación real, podemos terminar con una gran numero de controladores y muchas acciones en las que el código de auditoria se repite. Basados en el principio DRY (Don't repeat yourself), debemos refactorizar este código.

Un punto de extensibilidad importante del framework MVC son los filtros de acción (ActionFilter's).

Un filtro de acción te permite interceptar el pipeline de ejecución de las acciones, en dos puntos importantes: antes de que la acción sea ejecutada y después de que la acción se ejecutó en el controlador, pero justo antes de ser enviada la respuesta al usuario.

La siguiente imagen he tratado de aclarar este punto.
Action Filter - MVC Pipeline

Como construir un filtro de acción

El framework MVC define puntos de extensión a través de clases base (abstractas en su mayoría) e interfaces que podemos implementar. Para crear un action filter debemos echar un vistazo en la interfaz System.Web.Mvc.IActionFilter.

Como pueden observar, esta interfaz define dos métodos que debemos implementar, uno que se ejecuta antes de invocar la acción en el controlador (OnActionExecuting) y una después de que es ejecutado (OnActionExecuted).

NOTA: Para poder aplicar un filtro de acción como un atributo en una acción o controlador, debemos heredar de la clase System.Web.Mvc.FilterAttribute.

Recapitulando nuestro problema

En nuestro caso, para evitar el código duplicado queremos mover las líneas de código que se encargan de setear los valores de UserId e IP a un filtro de acción.

1. Refactorizar

1.Para poder refactorizar nuestro código, lo primero que haremos será tener una interfaz común para las clases que sirvan de parámetros en nuestras acciones, crearemos la interfaz IAuditRequest, con el siguiente código.

Como pueden ver solo he definido lo que tienen en común todos los modelos a los que aplicamos auditoria.

  1. Hacemos que nuestras clases que sirven de modelos para nuestras acciones y necesiten ser auditadas implemente nuestra interfaz, como se puede ver en el siguiente ejemplo.

2. Crear el actionFilter

  1. Agregamos una nueva clase a nuestro proyecto de ASP.net MVC en el lugar que ustedes prefieran, esta clase la llamaremos AuditFilter.

  2. Hacemos que la clase herede de FilterAttribute e implemente la interfaz IActionFilter, de la que hablamos líneas más arriba.

  1. El parámetro filtercontext nos da acceso a un sin número de propiedades con las que podemos acceder a la acción que se está ejecutando, sus parámetros, el controlador, la request, el response, etc. En nuestro caso queremos acceder al parámetro de nuestra acción al cual podamos asignar las propiedades de auditoria.
    Para acceder a los parámetros de la acción, usamos la propiedad filterContext.ActionParameters.
  1. Para acceder al objeto Request y User que usábamos en la acción del controlador utilizamos la propiedad filterContext.HttpContext.Request y filterContext.HttpContext.User.

5.Finalmente, agregamos un par de líneas para hacer nuestro filtro más genérico.

Momento de probar

Ahora que tenemos nuestro action filter creado, procederemos a probarlo en acción.
Primero removemos las líneas de código que tenemos en nuestras acciones, en las que antes manualmente fijábamos las propiedades de auditoria.

Decoramos las acciones o controladores a las que queremos aplicar nuestro filtro.

Si ejecutamos nuestra aplicación y accedemos a nuestra acción, podremos ver como nuestro actionFilter se ejecuta primero (onActionExecuting).

Después de pasar por la ejecución de nuestro filtro, las propiedades de auditoria son aplicadas correctamente.

Y finalmente continua la ejecución normal y pasa a ejecutarse el código de nuestra acción en el controlador.

Conclusiones

Los filtros de acción pueden ser herramientas útiles a la hora de reducir el código repetido ya que nos permiten interceptar la ejecución de nuestras acciones e inyectar nuestra propia lógica. Espero les sirva ;)