domingo, 18 de agosto de 2013

Ejemplo MVC - Controladora base / Evento OnActionExecute

Para el inicio de la serie Ejemplos MVC vamos a ver sel siguiente ejemplo:

Crear una clase abstracta controladora y sobrescribir evento OnActionExecute
El ejemplo sirve para: 
  1. Tener Constructor/Objetos/propiedades/Dispose comunes para todos los controladores.
  2. Uso centralizado de sesiones y facilitar pruebas unitarias.
  3. Gestión de permisos.

Si heredamos las controladoras de la aplicación de una clase abstracta, podemos añadir objetos y/o propiedades comunes en el constructor. 

Primer paso. Clase abstracta básica de ejemplo

public abstract class ControllerBase:Controller
{
        protected IAplicacion oApp;
        protected BDEntities db = new BDEntities();

        public ControllerBase()
        {
        }

        protected override void Dispose(bool disposing)
        {
            db.Dispose();
            base.Dispose(disposing);
        }
}

Con este código se consigue:
Tener objetos comunes compartidos por todos los controladores. En el ejemplo un objeto tipo IAplicacion y BDEntitie. Son dos ejemplos básicos, IAplicacion es un ejemplo tipo de una interfaz con un objeto/s básico/s necesario en toda nuestra aplicación: Usuario, Permisos, Breadcrumbs, etc... BDEntitie representa un objeto de Entity Framework, también muy común en todo controlador de cualquier aplicación que use Entity.
Tener un constructor común de inicialización, en este caso ControllerBase, que está vacio.
Destructor común que liberará los recursos.

Segundo paso. Sobrescribir evento OnActionExecute
Además, si sobrescribimos el evento OnActionExecute en la clase base, podemos tratar de forma centralizada el estado del contexto http, es decir principalmente las sesiones. Esto permite facilitar la gestión de las mismas al estar centralizado, y a la vez facilita las pruebas unitarias. El evento OnActionExecute, es un evento del contexto http, y no se ejecuta al realizar las pruebas, por tanto facilita tener que hacer mocking del contexto de la sesión, bastará con hacer mocking de la interfaz de aplicación IAplicacion para realizar las pruebas. 
No obstante, quiero aclarar que esta es una solución para centralizar el contexto http y evitar tener que simularlo en las pruebas, sin embargo también es posible hacer mocking de las sesiones, dejo un link de ejemplo. 

protected override void OnActionExecuting(ActionExecutingContext ctx)
{
   //En la pantalla de Login NO se comprueba estado sesión.
    if (ctx.ActionDescriptor.ControllerDescriptor.ControllerName == "Login") return;

   //Recoger variable de sesión objeto Aplicación.
   oApp = System.Web.HttpContext.Current.Session[Constantes.sesApp] as Aplicacion;

   //Chequear permisos (Se trata este tema en el siguiente Post)

   if (oApp.Permisos.TienePermiso){
    //Si tiene permisos sigue el flujo de ejecución
    base.OnActionExecuting(ctx);
    return;
   }

   //Si no tiene permisos se limpia la sesión
   System.Web.HttpContext.Current.Session.Clear();
   //Redirige a pantalla de Login
    ctx.Result = RedirectToAction("Index", "Login");
}

Tercer paso: Declarar todos los controladores como heredados de la clase ControllerBase.
                    Declarar constructor que recibe por parámetro la interfaz IAplicacion.
Se consiguen controladores limpios de variables de sesión, fáciles de testear simulando el estado del objeto oApp, simulando el objeto/estado deseado a través de la interfaz IAplicacion.
La clave está en que al ejecutar los controladores el estado del objeto oApp se recoge de sesión, y al realizar las pruebas se le pasa falsificado(mockeado) por parámetro al constructor. Al estar el tratamiento de la sesión en el evento OnActionExecuting, no se producirá ninguna excepción.

    public class HomeController : ControllerBase
    {
        public HomeController(IAplicacion aplicacion)
        {
            oApp = aplicacion;
        }

        public ActionResult Index()
        {
           //Tu Código que hace uso de un objeto oApp(de IAplicacion)
        }
    }




No hay comentarios:

Publicar un comentario