Controladores todavía más automáticos

ASP.NET MVCHace algún tiempo experimentábamos con controladores capaces de implementar automáticamente la lógica de acciones cuya misión era únicamente retornar la vista por defecto.

Así, partíamos de un controlador como el siguiente:

public class HomeController: Controller
{
    public ActionResult Index()
    {
        return View();
    }
 
    public ActionResult Company()
    {
        return View();
    }   
 
    public ActionResult Services()
    {
        return View();
    }
    
    public ActionResult Contact()
    {
        return View();
    }
    
}

Y veíamos cómo simplemente heredando de la clase AutoController que definíamos en el mismo post, podíamos omitir la implementación de las acciones anteriores, consiguiendo un código mucho más compacto:

public class HomeController: AutoController
{
}

Está claro que utilizando como base la clase AutoController hemos ahorrado mucha codificación, pero, perezosos como somos, seguro que todavía estamos escribiendo más de la cuenta.

Si el único código que vamos a tener en un controlador es la definición de la propia clase, quizás podamos hacer algo para evitar incluso tener que codificar eso, ¿no? De la misma forma que hicimos con las acciones, seguro que podríamos crear un controlador por defecto para procesar las peticiones entrantes para las que no podamos encontrar un controlador específico.

¡A por la factoría de controladores!

La factoría de controladores es el componente de ASP.NET MVC encargado de localizar e instanciar el controlador apropiado para procesar cada petición entrante. Por defecto, este trabajo lo realiza la clase DefaultControllerFactory, pero como en otras ocasiones, la flexibilidad del framework MVC permite sustituir muy fácilmente este componente por otro que realice la tarea que nos interesa.

Dentro de la factoría de controladores, el método GetControllerType() es utilizado por el framework para localizar el tipo (la clase) de controlador en función del nombre obtenido desde los parámetros de ruta. De hecho, este mismo método es el que utilizamos hace más de un año para saltarnos a la torera la convención de nombrado de controladores del framework.

De hecho, si heredamos de la factoría de controladores por defecto, basta con sobrescribir este método GetControllerType() para conseguir el comportamiento que pretendemos. En primer lugar, ejecutamos la lógica por defecto; sólo en el caso de no encontrar un controlador utilizaremos por defecto el controlador AutoController que creamos en el post anterior, de forma que sea él el que se encargue de proporcionar la implementación automática de sus acciones:

public class AutoControladoresControllerFactory: DefaultControllerFactory
{
    protected override Type GetControllerType(RequestContext requestContext, 
                                              string controllerName)
    {
        return base.GetControllerType(requestContext, controllerName) 
               ?? typeof (AutoController);
    }
}

Ya lo último que necesitamos es indicar al framework la factoría de controladores que debe utilizar, la clase AutoControladoresControllerFactory, introduciendo el siguiente código en el archivo global.asax.cs:

protected void Application_Start()
{
    // Establecemos la nueva factoría de controladores...
    ControllerBuilder.Current.SetControllerFactory(
                                typeof(AutoControladoresControllerFactory)
                              );
 
    // Y el código habitual en el Application_Start()
    AreaRegistration.RegisterAllAreas();
    RegisterRoutes(RouteTable.Routes);
}

Y con eso, hemos terminado. A partir de ese momento, todas las peticiones cuyo controlador sea imposible localizar según el procedimiento estándar, serán procesadas por el controlador automático AutoController, que buscará para cada acción una vista y la retornará mágicamente al usuario.

imageAsí, una petición de tipo GET /Home/Services, que requeriría normalmente la existencia de una clase controlador HomeController y un método de acción Services(), podrá ser resuelta sin implementar ninguno de estos dos elementos, siempre que exista una vista definida en ~/Views/Home/Services.aspx.

Ya en el post anterior comenté algunas contraindicaciones que podía tener la utilización de esta técnica. ¡No dejes de revisarlo si piensas emplearla en producción!

A modo de demo, he colgado en Skydrive un ejemplo (para Visual Studio 2010) en el que se ha eliminado directamente el controlador Home, y han sido añadidas diversas vistas a las que se puede acceder utilizando estos automatismos.

Publicado en: Variable not found.

2 comentarios en “Controladores todavía más automáticos”

  1. Buenas!
    Al margen de un pequeño error sin importancia (donde dices al final “siempre que exista una vista definida en /views/home/products.aspx” entiendo que debería ser “/views/home/services.aspx”), un artículo EXCELENTE.

    Como técnica para ser usada en prod, no me termina de convencer (aunque se me ocurren un par de situaciones donde estos controladores “autogenerados” encajarían perfectamente), es un genial ejemplo de lo que podemos hacer con MVC!

    Un saludo!

  2. Gracias, Eduard.

    Bueno en producción esto tiene sus peligros e inconvenientes, por lo que debería ser utilizado con muuucha precaución. De todas formas, no deja de ser un experimento interesante con la factoría de controladores 🙂

    En cuanto al error tienes razón, gracias por avisar… (obviamente lo había dejado ahí adrede, para ver si estabas atento ;-DDDD)

    Saludos!

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *