ASP.NET MVC vNext – Controladores “POCO”

Una de las novedades que presenta ASP.NET MVC6 (integrada dentro de vNext) es la posibilidad de que los controladores ya no deban heredar de ninguna clase base.

De hecho la clase Controller en MVC clásico (MVC5 y anteriores) proporcionaba básicamente dos cosas:

  1. Un conjunto de métodos de para devolver action results (p. ej. el método View() para devolver un ViewResult o el método Json para devolver un JsonResult).
  2. Acceso a algunas propiedades para contexto (ControllerContext, ModelState y ViewBag básicamente).

Los métdos para devolver action results no son estríctamente necesarios (aunque ayudan) pero pueden encapsularse en alguna clase aparte y los objetos de contexto pueden añadirse por inyección de dependencias (ASP.NET vNext está montando desde la base usando inyección de dependencias).

Así en MVC6 podemos crear un controlador como el siguiente:

  1. public class HomeController
  2. {
  3.     // GET: /<controller>/
  4.     public IActionResult Index()
  5.     {
  6.         return null;
  7.     }
  8. }

Si (asumiendo la tabla de rutas tradicional) navegamos hacia /Home/Index veremos como se nos invoca dicho método. Por supuesto ahora hemos de ver como crear el action result necesario. P. ej. supongamos que queremos devolver la vista (lo que sería un return View() en un controlador tradicional). Vemos que el constructor del ViewResult nos pide dos parámetros:

image

Como he dicho antes ASP.NET vNext está montado basado en inyección de dependencias así que… deja que el propio framework te inyecte estos parámetros:

  1. public class HomeController
  2. {
  3.     private readonly IServiceProvider _serviceProvider;
  4.     private readonly IViewEngine _viewEngine;
  5.     public HomeController(IServiceProvider serviceProvider, IViewEngine viewEngine)
  6.     {
  7.         _serviceProvider = serviceProvider;
  8.         _viewEngine = viewEngine;
  9.     }
  10.     public IActionResult Index()
  11.     {
  12.         return new ViewResult(_serviceProvider, _viewEngine);
  13.     }
  14. }

Si ahora ejecutas y colocas un breakpoint en el constructor verás que ambos parámetros han sido inicializados por el framework de ASP.NET vNext:

image

Verás como efectivamente esto devuelve la vista Index.cshtml localizada en Views/Home (exactamente lo mismo que hace return View()).

Pasar un modelo a la vista tampoco es excesivamente complicado:

  1. public class HomeController
  2. {
  3.     private readonly IServiceProvider _serviceProvider;
  4.     private readonly IViewEngine _viewEngine;
  5.     private readonly IModelMetadataProvider _modelMetadataProvider;
  6.     public HomeController(IServiceProvider serviceProvider, IViewEngine viewEngine, IModelMetadataProvider modelMetadataProvider)
  7.     {
  8.         _serviceProvider = serviceProvider;
  9.         _viewEngine = viewEngine;
  10.         _modelMetadataProvider = modelMetadataProvider;
  11.     }
  12.     public IActionResult Index()
  13.     {
  14.         var viewdata = new ViewDataDictionary<FooModel>(_modelMetadataProvider);
  15.         viewdata.Model = new FooModel();
  16.         return new ViewResult(_serviceProvider, _viewEngine) { ViewData = viewdata };
  17.     }

Necesitamos un IModelMetadataProvider (que recibimos también por inyección de dependencias) ya que lo necesitamos para la construcción del ViewDataDictionary que pasamos a la vista.

Para evitar que nuestro controlador POCO deba tomar demasiadas depenencias en el constructor (dependencias que son requeridas básicamente para construir los action results), el equipo de ASP.NET ha creado la interfaz IActionResultHelper. Dicha interfaz contiene métodos para ayudarnos a crear más fácilmente los action results. Por supuesto, en el controlador recibimos un IActionResultHelper por inyección de dependencias. Así podemos modificar nuestro controlador para que quede de la siguiente forma:

  1. public class HomeController
  2. {
  3.     private readonly IActionResultHelper _actionHelper;
  4.     private readonly IModelMetadataProvider _modelMetadataProvider;
  5.     public HomeController(IActionResultHelper actionHelper, IModelMetadataProvider modelMetadataProvider)
  6.     {
  7.         _actionHelper = actionHelper;
  8.         _modelMetadataProvider = modelMetadataProvider;
  9.     }
  10.     public IActionResult Index()
  11.     {
  12.         var viewdata = new ViewDataDictionary<FooModel>(_modelMetadataProvider);
  13.         viewdata.Model = new FooModel();
  14.         return _actionHelper.View("Index", viewdata);
  15.     }
  16. }

Ahora el controlador solo toma una dependencia contra el IActionResultHelper y el IModelMetadataProvider. Las dependencias contra el IServiceProvider y el IViewEngine (que eran solo para crear el ViewResult) son gestionadas ahora por el IActionResultHelper.

¡Y listos! Hemos visto como podemos crear controladores POCO (que no hereden de Controller) y como a través de la inyección de dependencias ¡recibimos las dependencias necesarias de forma automática!

¡Saludos!

2 comentarios en “ASP.NET MVC vNext – Controladores “POCO””

Deja un comentario

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