Actualización del código de ASP.NET MVC

Hace poco creamos un proyecto ASP.NET  en CodePlex que usaremos para poner ahí (con el código fuente) las nuevas características y releases de ASP.NET

El mes pasado lo usamos para poner la primera versión del código de ASP.NET MVC. Esta primera versión se corresponde con la Preview 2 que presentamos en el MIX, junto con los archivos de proyecto de Visual Studio para que podamos compilarlas y montarlas en local.

Hace unas horas publicamos una nueva versión del código. Esta versión no es una versión oficial de ninguna release de ASP.NET MVC - sino una versión intermedia para ver cómo está el estado del arte del código. Publicaremos la release 3 de ASP.NET MVC en unas semanas, después de terminar algún que otro trabajo (nuevas características y mejoras en otras ya existentes, mejor integración en VS, soporte en las versiones express de VS, documentación, etc). Si eres de los que quiere una instalación de ASP.NET MVC con documentación y soporte total de la herramienta, querrás esperar a la publicación de una preview oficial. Si quieres investigar y ver qué se está haciendo de nuevo, esta preview de la preview es tu oportunidad para empezar a usarla y darnos algún feedback.

Mejoras en el código de ASP.NET MVC

En esta actualización (que podéis descargar aquí) se incluyen algunas mejoras. Entre las que están:

  • Además de poner el código fuente del framework de ASP.NET MVC, también hemos publicado los test unitarios que usamos. Estos test están hechos con MSTest y el framework Mog. También incluimos el archivo de proyecto para VS con los test de manera que sea más fácil ejecutarlos localmente.
  • Mayor soporte para testeo de las clases Controladoras. Ahora podéis crear test en las controladoras sin tener que hacer objetos mock.
  • Varias mejoras en la usabilidad del sistema de rutado de urls.

Crear un nuevo proyecto ASP.NET MVC

Podemos tener una copia de los assemblies de MVC descargando el código y compilarlo localmente, o descargar el paquete de templates para Visual Studio para tener una versión precompilada de ellos.

Después de instalar el template .VSI, aparecerá un nuevo template en Visual Studio llamado "ASP.NET MVC Application" en la sección "My Templates" en el diálogo "New Project":

Esta nueva versión del template de MVC puede coexisitir con las versiones anteriores (ya lo podéis ver en la imagen anterior). Permitiendo de esta forma crear nuevos proyectos y usar la última versión del código ó la versión de la preview oficial en la misma máquina.

Cuando creamos un proyecto nuevo con la nueva versión, tendremos un proyecto con la siguiente estructura:

Esta solución contiene un controlador ("HomeController") en el directorio "Controllers" y dos vistas ("About" y "Index") en el directorio "ViewsHome". Ambas vistas están basadas en una master page ("Site.master") que tiene definida toda la css en "site.css" en el directorio "Content".

Si ejecutamos la aplicación tendremos lo siguiente:

Si hacemos clic en el tab "About us" tendremos:

La clase "HomeController" es la responsable de administrar las dos urls anteriores y tiene dos métodos de acción:

El template "Site.master" busca el valor "Title" en la colección ViewData y la usa para renderizar el elemento <title> de la página. La vista "Index" busca el valor "Message" y lo usa para renderizar la página de bienvenida. Obviamente podemos personalizar estos archivos como queramos.

Cambios en los controladores de esta nueva versión

Si os habéis fijado bien, os habréis dado cuenta de un par de cosillas sobre cómo están implementadas las clases controladoras.

En la preview 2 la clase anterior tendría el siguiente código:

El equipo de MVC está experimentando con unas cuantas ideas en esta versión del código:

  1. Los métodos de acción devuelven un objeto del tipo "ActionResult" en lugar de void. Este objeto indica el resultado de la acción (una vista a renderizar, una url a la que redireccionar, otra acción a ejecutar, etc).
  2. Los métodos RenderView(), RedirectToAction() y Redirect() de la clase base Contorlador también devuelven objetos ActionResult (que podremos manipular o devolver desde los métodos de acción).
  3. El método RenderView() puede llamarse sin tener que pasar el nombre de la vista a renderizar. Si no le pasamos ningún nombre, el método renderizará por defecto la vista con el nombre del método de acción. Así que llamar a RenderView sin parametros en el método de acción "About()", sería lo mismo que escribir "RenderView('About')"

Es realmente simple actualizar las clases controladoras a esta Preview 2 usando este nuevo patrón (sólo cambiar el void a ActionResult y añadir una sentencia return delante de cualquier método RenderView o RedirectToAction).

Devolver objetos ActionResult en los métodos de acción

¿Pero porqué cambiar esto? Varios frameworks MVC muy populares usan esta solución (como Django, Tapestry y otros), y creemos que aportará grandes beneficios a ASP.NET MVC:

  1. Permite una forma más clara y sencilla de crear test para las clases controladoras. No tendremos que usar objetos mocks en los objetos Response o ViewEngine para ver si todo ha ido bien. Sólo con añadir los asserts necesarios que usen estos objetos en las llamadas a los métodos de acción.
  2. Hace que el flujo de la lógica de las clases controladoras sea más claro y explícito en escenarios donde queramos tener dos formas diferentes de actuar dependiendo de alguna condición (por ejemplo: redireccionar si la condición A es verdadera, o renderizar una vista si es falsa). Esto puede hacer que el código no trivial de un método de acción sea más fácil de leer y seguir.
  3. Permite escenarios de composición en donde un FilterActionAttribute pueda coger el resultado de un método de acción y modificarlo ántes de que se ejecute. Por ejemplo: una acción "Browse" en un controlador de ProductCatalog puede devolver un RenderActionResult que indica que queremos renderizar una lista de productos. Un FilterActionAttirute puede personalizar esta vista de productos a List-html.aspx o a List-xml.aspx dependiendo del tipo MIME del cliente.
  4. Aporta un mecanismo extensible para personas (incluidos nosotros) que quieran añadir nuevas características en el futuro. Se pueden crear nuevos tipos ActionResult heredando de ActionResult y sobreescribir el método "ExecuteResult". Sería muy sencillo crear un método "RenderFile()", por ejemplo, al que un desarrollador pueda llamar devolviendo un objeto "FileActionResult".
  5. Permite también escenarios de ejecución asíncrona en el futuro. Los métodos de acción serán capaces de devolver objetos del tipo AsyncActionResult que indiquen que están esperando una operación de red y que queremos volver al thread en eejcución de manera que ASP.NET lo usase para ejcutar otra petición hasta que la llamada de red terminase. Esto nos permitirá evitar bloqueos de threads en el servidor, y soportarán un código muy eficiente y escalable.

Uno de los objetivos de esta versión no oficial es dar a la gente una oportunidad para que juege con estas cosas y que hagan aplicaciónes reales y aprendan con ello.

También postearemos una clase Controller base alternativa para que podamos usar métodos de acción que devuelvan void. No publicamos esta versión en la nueva versión deliberadamente, ya que queremos darle una oportunidad a los ActionResult para ver si gusta o no.

Cómo testear métodos de acción.

Hemos hablado sobre los tipos ActionResult para hacer test unitarios en las clases controladoras mucho más sencillas (evitando tener que usar objetos mocks). Veamos un ejemplo:

Imaginemos la siguiente clase:

Esta clase tiene un método de acción "IsEvenNumber" que toma el parámetro desde la URL. Este método comprueba si es negativo - en ese caso redirecciona a una página de error. Si es positivo comprueba si es par o impar, y dependiendo de eso renderiza una vista u otra:

Crear un test unitario para este método es muy fácil gracias a los ActionResult.

Aquí tenéis un ejemplo de un test que comprueba la corrección de la redirección Http cuando se da un número negativo (por ejemplo: /Number/IsEvenNumber/-1):

Fijáos que no hemos tenido que usar un mock object para testear el método. Sino que sólo hemos instanciado la clase NumberController y hemos llamado al método de acción directamente (pasándole un número negativo) y asignándole el resultado a una variable local "result". He usado el comando "as type" de C# para hacer un casting de la variable "result" como un tipo fuertemente tipado "HttpRedirectResult".

Lo sencillo del comando "as" de C# es que asignará un valor null en lugar de elevar una excepción si el casting falla (por ejemplo: si el método devuelve un RenderViewResult). Con esto podemos añadir assertions en nuestros test para comprobar que el resultado no es nullo para comprobar que la redirección ha ocurrido. Ahora puedo añadir un segundo assert para comprobar que la dirección url es la correcta.

Testear los escenarios en los que se pasan números que no sean 0 también es fácil. Par ahacer esto crearemos dos métodos de test -uno para comprobar numeros pares y otro para los impares. En ambos casos comprobaremos el RenderViewResult que se ha devuelto, y comprobaremos el string "Message" que se le pasó con el ViewData asociado:

Haciendo clic derecho en la clase NumberControllerTest podemos ejecutar el tes:

Esto ejecutará los tres test en memoria (no hace falta un servidor web) y nos informará si el método de acción  NumberController.IsEvenNumber() está comportándose de la manera esperada:

Nota: En la versión de esta semana seguimos necesitando objetos mock para testear la propiedad TempData. Nuestros planes son no necesitar en ASP.NET MVC Preview 3 estos objetos en ningún lugar.

Le método MapRoute

Las reglas de rutado url en ASP.NET MVC son declaradas en el método "RegisterRouters" de la clase Global.asax.

En las preview 1 y 2 de ASP.NET MVC las retlas de rutado se añadían a esta colección instanciando un objeto Route directamente y enlazándola a la clase MvcRouteHandler,  configurabamos sus propiedades:

El código anterior continuará funcionando. Sin embargo, también podemos usar el método "MapRoute" que nos aporta una sintaxis más simple para hacer lo mismo. Aquí tenéis la ruta por defecto que se añade cuando creamos un proyecto MVC:

El método MapRoute tiene está sobrecargado y tiene dos, tres o cuatro parámetros (nombre, sintaxis parámetros por defecto y una expresion regular).

Podemos llamarlo las veces que necesitemos para registrar varias rutas del sistema. por ejemplo, además de la regla por defecto, podemos añadir una ruta llamada "Products-Browse" de la siguiente forma:

Ahora podemos referirnos a la regla "Products-Browse" explícitamente en los controladores y vistas cuando queramos generar una url hacia ella. Por ejemplo, podemos usar la vista HTml.RouterLink para indicar quequeremos un enlace a la ruta "Products-Browse" y pasarle la categoría "Food" con el siguiente código:

Este métdo accederá al sistema de rutado y devolverá el link HTML necesario:

Nota: en la versión de esta semana necesitamos pasarle el controlador y las acciones como parámetros (además de la categoría) al Html.RouteLink() para que se genere la url adecuada. La preview 3 de ASP.NET MVC no necesitará esto, y nos permitirá usar la llamada Html.RouteLink como la he escrito antes.

Otras características del mapeado de rutas url

La versión de esta semana también soporta varias nuevas características en el mapeo de rutas url. Podemos inluir "-", ".", ";"  o cualquier caracter que queramos en nuestras reglas de rutado.

Por ejemplo, usar el operador "-" podemos parsear el lenguaj y valores locales de nuestras urls con la siguiente regla:

Esto pasará los parámetros "language", "locale" y "category" al método de acción ProductsController.Browse:

URL Route Rule Example URL Parameters Passed to Action method
{language}-{locale}/products/browse/{category} /en-us/products/browse/food language=en, locale=us, category=food
  /en-uk/products/browse/food language=en, locale=uk, category=food

O podemos usar la extensión de archivos "." al final de la url para determinar cuándo devolver el formato en XML o HTML:

Esto le pasará los parámetros "category" y "format" al método de acción ProductsController.Browse cuando se le invoque:

URL Route Rule Example URL Parameters Passed to Action method
products/browse/{category}.{format} /products/browse/food.xml category=food, format=xml
  /products/browse/food.html category=food, format=html

ASP.NET MVC Preview 2 introdujo reglas wildcard. Porj ejemplo, podemos indicar en la regla que se le pase el resto del contenido URI como un nombre parametrizado al método de acción:

De esta manera pasamos el parámetro "contentUrl" al método de acción WikiController.DisplayPage:

URL Route Rule Example URL Parameters Passed to Action method
Wiki/Pages/{*contentUrl} /Wiki/Pages/People/Scott contentUrl="People/Scott"
  /Wiki/Pages/Countries/UK contentUrl="Countries/UK"

Estas rutas continuarán funcionando bien con la preview de esta semana - y es muy útil hecharle un vistazo si estamos creando un blog, wiki, cms o cualquier otro sistema de contenidos.

Fijaos que además de usar el nuevo sistema de rutas de ASP.NET MVC, también podemos usar el mismo sistema con ASP.NET Dynamic Data (que usa ASP.NET Web Forms).

Resumen

Hemos visto una rápida introducción a las nuevas características que aparecen en la última versión del código de ASP.NET MVC

Podéis descargarlo aquí si queréis empezar a usarlo ya. También podemos esperar unas semanas para tener la versión oficial de la preview 3 de ASP.NET MVC - que tendrá más características (e incorporará el feedback de los que han probado la versión de esta semana), un instalador más parecido, mayor integración con VS, y una documentación actualizada.

Si queréis hacer preguntas sobre esta versión, mirad el foro de msdn de MVC en www.asp.net

Espero que sirva.

Scott

Traducido por: Juan María Laó Ramos.

Artículo original.

Un pensamiento en “Actualización del código de ASP.NET MVC

  1. Pingback: ASP.NET MVC Preview 3 « Thinking in .NET

Deja un comentario