Вы находитесь на странице: 1из 27

Tu mejor ayuda para aprender a hacer webs www.desarrolloweb.

com

Manual del framework ASP.NET MVC


Manual dedicado al framework de ASP.NET MVC, basado en el patrn Modelo - Vista Controlador, para el desarrollo de aplicaciones web con tecnologas Microsoft.

Autores del manual


Este manual ha sido realizado por los siguientes colaboradores de DesarrolloWeb.com:
Eduard Toms

Technology Specialist en raona http://geeks.ms/blogs/etomas (8 captulos)

Manual del framework ASP.NET MVC: www.desarrolloweb.com/manuales/framework-asp-net-mvc.html


Los manuales de DesarrolloWeb.com tienen el copyright de sus autores. No reproducir sin autorizacin.

Tu mejor ayuda para aprender a hacer webs www.desarrolloweb.com

Introduccin a ASP.NET MVC


ASP .NET MVC es el nuevo framework que ha sacado Microsoft para desarrollar aplicaciones web, usando tecnologa .NET. Lo de nuevo entre comillas, viene porque la primera versin sali, aproximadamente, a mediados del 2009 y ya sabemos que en este mundo, casi dos aos son una eternidad. De hecho, actualmente el framework ya va por su tercera versin y es esa tercera versin la que vamos a ver en esta serie de artculos. ASP.NET MVC 3.0 permite el desarrollo de aplicaciones web usando .NET Framework 4.0 y Visual Studio 2010. No puede usarse Visual Studio 2008 aunque s la versin Express (gratuita) de Visual Web Developer. ASP.NET MVC 3.0 no viene de serie, ni con Visual Studio 2010 ni con Visual Web Developer 2010. Puede instalarse usando Web Platform Installer o bien descargndolo desde http://www.microsoft.com/downloads/en/details.aspx?FamilyID=d2928bc1-f48c-4e95-a0642a455a22c8f6&displaylang=en

Sustituye ASP.NET MVC a ASP.NET?


Esta es una de las primeras preguntas que se realiza mucha gente cuando oye a hablar por primera vez del Framework. La respuesta es un rotundo no, y por dos razones principales: 1. ASP.NET MVC est construido usando ASP.NET. Todos los aspectos transversales de ASP.NET (autenticacin, cache, sesin, roles,) siguen siendo los mismos en ASP.NET MVC. 2. Si a algo puede sustituir ASP.NET MVC es a Webforms, es decir a las pginas .aspx. Pero Microsoft ya ha anunciado que esto no suceder: ambos frameworks (ASP.NET MVC y Webforms) se seguirn evolucionando. As pues si has invertido tiempo en conocer y dominar Webforms, estate tranquilo: ese conocimiento sigue siendo vlido. De todos modos yo te animo a que eches un vistazo a ASP.NET MVC y luego decidas cul de los dos frameworks te gusta ms para el desarrollo de aplicaciones web usando .NET.

El Patrn Modelo - Vista - Controlador (MVC)


ASP.NET MVC es, bsicamente, una implementacin del patrn Modelo - Vista - Controlador (MVC) para tecnologa ASP.NET. El patrn MVC no es ni nuevo (data de finales de los aos 70) ni est pensado para aplicaciones web, pero en realidad en aplicaciones web encaja perfectamente. Brevemente podemos decir que el patrn MVC separa la lgica (y acceso a datos) de una aplicacin de su presentacin, usando 3 componentes: 1. Modelo: Representa las reglas de negocio de la aplicacin (y el acceso a datos subyacente). 2. Vistas: Representan la presentacin de la aplicacin. 3. Controlador: Actan de intermediario entre el usuario y el Modelo y las Vistas. Recogen las peticiones del usuario, interaccionan con el modelo y deciden que vista es la que debe mostrar los datos. En el contexto de ASP.NET MVC: Toda la lgica de negocio y el acceso a datos es el Modelo (en muchos casos el Modelo puede estar en uno o varios assemblies referenciados). Las vistas contienen, bsicamente, el cdigo que se enva al navegador, es decir el cdigo HTML (y cdigo de servidor asociado, siempre y cuando este cdigo haga cosas de presentacin, no de lgica de negocio). Los controladores reciben las peticiones del navegador y en base a esas, deciden que vista debe enviarse de vuelta al navegador y con qu datos.

Manual del framework ASP.NET MVC: www.desarrolloweb.com/manuales/framework-asp-net-mvc.html


Los manuales de DesarrolloWeb.com tienen el copyright de sus autores. No reproducir sin autorizacin.

Tu mejor ayuda para aprender a hacer webs www.desarrolloweb.com

Ventajas de ASP.NET MVC


La ventaja que primero salta a la vista de ASP.NET es la facilidad con la que se generan URL semnticas, es decir URL que tengan la forma http://servidor/ver/productos/cafeteras en lugar de http://servidor/productos/ver.aspx?code=cafeteras. Las URLs semnticas se indexan mejor en los buscadores y son una prctica SEO habitual. No es que en webforms no se puedan hacer, es que en ASP.NET MVC vienen de serie. Otras ventajas, ms a nivel tcnico, son que con ASP.NET MVC se facilita mucho el probar nuestra aplicacin (especialmente usando pruebas unitarias) y que el uso correcto del patrn MVC facilita la reutilizacin de cdigo de manera mucho ms efectiva que en webforms. Por supuesto, todo esto tiene un precio: la curva de aprendizaje de ASP.NET MVC puede ser ms alta que la de webforms, especialmente si nunca has desarrollado para web. A diferencia de webforms, que te abstrae de HTTP y HTML, ASP.NET MVC est "mucho ms cerca de la web", lo que hace necesario conocer HTTP, HTML y Javascript para trabajar con l. De todos modos eso no debera echarte para atrs: si quieres crear aplicaciones web es normal que debas conocer los protocolos y lenguajes en los que se asenta la web, no? A lo largo de esa serie de artculos, que vamos a publicar en el Manual de ASP.NET MVC, iremos viendo cmo desarrollar una aplicacin ASP.NET MVC, usando la versin 3.0 del framework.
Artculo por

Eduard Toms

Manual del framework ASP.NET MVC: www.desarrolloweb.com/manuales/framework-asp-net-mvc.html


Los manuales de DesarrolloWeb.com tienen el copyright de sus autores. No reproducir sin autorizacin.

Tu mejor ayuda para aprender a hacer webs www.desarrolloweb.com

La primera aplicacin ASP .NET MVC


Vamos a ver cmo paso a paso realizar el, ya tpico, Hola Mundo usando ASP .NET MVC.

Creacin del proyecto


Una vez instalado ASP.NET MVC 3, nos aparece un nuevo tipo de proyecto en Visual Studio: ASP.NET MVC 3 Application:

Le damos el nombre que queramos (en este caso MvcHelloWorld) y el directorio donde se va a generar y listos. En el siguiente paso nos preguntar si queremos una aplicacin "Emtpy" o "Internet Application", y seleccionamos "Empty". La diferencia es que en el segundo caso ya se nos genera un conjunto de controladores y vistas por defecto, y ahora este cdigo nos liara ms que ayudara as que vamos a obviarlo. Con "Empty" empezamos con una aplicacin ASP.NET MVC vaca. El desplegable "View Engine" tiene dos valores: Razor y ASPX. Esto hace referencia a la tecnologa con la cual se implementan las vistas. Si seleccionamos ASPX nuestras vistas sern archivos .aspx, mientras que si usamos Razor nuestras vistas sern archivos .cshtml (o .vbhtml si usamos Visual Basic). Razor es una sintaxis nueva mucho ms compacta que ASPX y es, por tanto, la que vamos a usar nosotros.

Manual del framework ASP.NET MVC: www.desarrolloweb.com/manuales/framework-asp-net-mvc.html


Los manuales de DesarrolloWeb.com tienen el copyright de sus autores. No reproducir sin autorizacin.

Tu mejor ayuda para aprender a hacer webs www.desarrolloweb.com

Finalmente le damos a "Ok" y eso nos va a crear nuestro proyecto vaco.

Estructura de un proyecto ASP.NET MVC


Incluso en una aplicacin vaca, Visual Studio nos habr creado varias carpetas, y algunos archivos:

Manual del framework ASP.NET MVC: www.desarrolloweb.com/manuales/framework-asp-net-mvc.html


Los manuales de DesarrolloWeb.com tienen el copyright de sus autores. No reproducir sin autorizacin.

Tu mejor ayuda para aprender a hacer webs www.desarrolloweb.com

ASP.NET MVC sigue lo que se conoce como convention over configuration, es decir: en lugar de usar archivos de configuracin para ciertas tareas, se usan convenciones predefinidas. Y esas convenciones son reglas como las siguientes: 1. Las vistas se ubican en la carpeta View 2. Los controladores son clases cuyo nombre termina en Controller Las carpetas que nos crea Visual Studio por defecto son las siguientes: 1. 2. 3. 4. 5. Content: Para tener contenido esttico (imgenes, hojas de estilo, ) Controllers: Para ubicar nuestros controladores Models: Para ubicar las clases del modelo. Scripts: Para tener archivos con cdigo javascript Views: Donde van las vistas de la aplicacin

Creacin del controlador y de la accin


Vamos a crear un controlador que se encargue de recibir la peticin del navegador (y que devuelva la vista que diga "Hola Mundo"). Para ello click con el botn derecho sobre la carpeta "Controllers" y seleccionar Add ' Controller. Visual Studio nos preguntar el nombre del controlador:

Podemos ver que por defecto el nombre termina con Controller. Modificamos para que en lugar de Default1Controller sea HomeController y le damos a Add. Eso nos crear una clase HomeController en la carpeta Controllers con el cdigo:
public class HomeController : Controller { //

Manual del framework ASP.NET MVC: www.desarrolloweb.com/manuales/framework-asp-net-mvc.html


Los manuales de DesarrolloWeb.com tienen el copyright de sus autores. No reproducir sin autorizacin.

Tu mejor ayuda para aprender a hacer webs www.desarrolloweb.com


// GET: /Home/ public ActionResult Index() { return View(); } }

Cosas que debemos observar: 1. La clase deriva de Controller 2. Tiene un mtodo pblico que devuelve un ActionResult y que se llama Index. Esto es una accin. Cualquier mtodo pblico de un controlador es por defecto una accin. En ASP.NET MVC toda peticin del navegador debe ser enrutada a una peticin (mtodo pblico) de un controlador. Por defecto se sigue la convencin de que las URLs estn en la forma http://servidor/controlador/accion. Es decir, para invocar la accin Index, del controlador Home, usaremos la URL: http://servidor/Home/Index. Fijaos en un detalle importante: la clase se llama HomeController pero el nombre del controlador es Home (sin Controller)

Creacin de la vista asociada


El cdigo de la accin que genera Visual Studio (return View();) lo que hace es devolver la vista asociada a dicha accin. Y aqu debemos tener presente otra convencin de ASP.NET MVC. Como se ha dicho antes las vistas cuelgan de la carpeta /Views. Por defecto, las vistas de un controlador: 1. Estn en una subcarpeta con el nombre del controlador 2. Se llaman igual que la accin Es decir, la vista de la accin Index del controlador Home, estar en la carpeta /Views/Home y se llamar Index. As pues creamos la carpeta (Add New Folder) Home dentro de Views y para aadir la vista, click con el botn derecho sobre la carpeta recin creada en el Solution Explorer y Add ' View. Eso nos despliega el dilogo de nueva vista:

Manual del framework ASP.NET MVC: www.desarrolloweb.com/manuales/framework-asp-net-mvc.html


Los manuales de DesarrolloWeb.com tienen el copyright de sus autores. No reproducir sin autorizacin.

Tu mejor ayuda para aprender a hacer webs www.desarrolloweb.com

Le ponemos "Index" como nombre y le damos a Add. Con eso Visual Studio nos habr generado un archivo Index.cshtml (situado en /Views/Home) con el cdigo:
@{ ViewBag.Title = "Index"; } <h2>Index</h2>

Ahora modificamos el cdigo HTML para aadir el Hello World:


@{ ViewBag.Title = "Index"; } <h2>Index</h2> Hola mundo. Saludos desde <strong>ASP.NET MVC</strong>

Manual del framework ASP.NET MVC: www.desarrolloweb.com/manuales/framework-asp-net-mvc.html


Los manuales de DesarrolloWeb.com tienen el copyright de sus autores. No reproducir sin autorizacin.

Tu mejor ayuda para aprender a hacer webs www.desarrolloweb.com Y listos! Con esto ya tenemos nuestra aplicacin lista. Para probarla basta ejecutarla (con F5) y comprobar los resultados:

Un ltimo detalle: Si os fijis la URL es simplemente http://localhost, sin nada ms y se est mostrando nuestra vista. Qu ha ocurrido? Pues que, por defecto si no se incluye controlador se asume que es "Home" y si no se entra accin se asume que es Index. Pero si entramos la URL completa vemos que tambin funciona:

Por otra parte si entramos un nombre de controlador o de accin que no existe, recibimos un 404 (pgina no encontrada):

Manual del framework ASP.NET MVC: www.desarrolloweb.com/manuales/framework-asp-net-mvc.html


Los manuales de DesarrolloWeb.com tienen el copyright de sus autores. No reproducir sin autorizacin.

Tu mejor ayuda para aprender a hacer webs www.desarrolloweb.com Un saludo a todos!


Artculo por

Eduard Toms

Pasar datos de los controladores a las vistas


En este artculo vamos a ver como pasar datos desde los controladores a las vistas. Hay tres mtodos (que realmente son dos) principales para pasar datos de los controladores a las vistas. Recordad que segn el patrn MVC, el controlador es quien accede al modelo para obtener los datos y mandrselos a la vista. La vista debe limitarse a mostrar esos datos (o a pedir datos nuevos y mandrselos de vuelta al controlador, lo que veremos ms adelante). Los datos que el modelo proporciona al controlador pueden venir de cualquier fuente (usualmente una base de datos).

Primer mtodo: ViewData


El primero de los mtodos es el denominado ViewData. ViewData es un diccionario de clave (una cadena) - valor (un objeto) que el controlador pasa a la vista. Un ejemplo de uso de ViewData es el siguiente controlador:
public class HomeController : Controller { public ActionResult Index() { ViewData["Nombre"] = "Eduard Toms"; ViewData["Twitter"] = "eiximenis"; return View(); } }

Aqu se define el controlador Home con la accin Index (recordad que las acciones son los mtodos pblicos que reciben las peticiones del navegador). En esta accin establecemos las claves Nombre y Twitter del ViewData y luego devolvemos la vista asociada a dicha accin. Para mostrar los datos en la vista, simplemente usamos la propiedad ViewData que tienen las vistas y que funciona exactamente igual. En este caso, en el cdigo de nuestra vista (archivo Home.cshtml que estara en la carpeta Home dentro de la carpeta Views) tendramos algo como:
<h2>Index</h2> Mi nombre es @ViewData["Nombre"] y puedes seguirme en <a href="http://twitter.com/@ViewData["Twitter"]">Twitter</a>.

Fijaos en dos cosas: 1. Para acceder a un valor del ViewData, simplemente usamos ViewData["clave"]. 2. Y muy importante: el uso de la arroba (@) antes de llamar a ViewData. Eso es parte de la sintaxis Razor (que veremos con detalle ms adelante, as que de momento no nos vamos a preocupar mucho de ella). El uso de ViewData tiene dos puntos dbiles que deben tenerse presentes: 1. Las claves son cadenas, por lo que si nos equivocamos el compilador no puede ayudarnos. Tampoco herramientas de refactoring pueden darnos soporte. 2. ViewData["clave"] siempre devuelve un object por lo que debemos ir haciendo casting si queremos obtener el tipo real de lo que hay almacenado. P.ej. En un controlador ponemos el siguiente valor en ViewData:
ViewData["FechaAlta"] = new DateTime(2008, 12, 10);

Este valor es un DateTime, no obstante si desde la vista queremos llamar a los mtodos de DateTime (como

Manual del framework ASP.NET MVC: www.desarrolloweb.com/manuales/framework-asp-net-mvc.html


Los manuales de DesarrolloWeb.com tienen el copyright de sus autores. No reproducir sin autorizacin.

10

Tu mejor ayuda para aprender a hacer webs www.desarrolloweb.com ToLongDateString()) deberemos hacer un casting: Dado de alta en: @(((DateTime)ViewData["FechaAlta"]).ToLongDateString()) Si no hiciramos el casting a DateTime, la llamada a ToLongDateString() generara una excepcin (aun cuando, en efecto, lo que hay en el ViewData["FechaAlta"] es un DateTime).

Segundo mtodo: ViewBag


ViewBag funciona de forma muy parecida a ViewData. Al igual que ViewData, ViewBag es un diccionario de clave - valor. Pero se aprovecha de las capacidades de programacin dinmica que ofrece C# 4, para en lugar de usar cadenas para especificar la clave, usar propiedades. As, desde una accin podemos hacer:
public ActionResult Index2() { ViewBag.Nombre = "Eduard Toms"; ViewBag.Twitter = "eiximenis"; ViewBag.FechaAlta = new DateTime(2008, 12, 10); return View(); }

Fijaos que el cdigo es casi igual al uso de ViewData, solo que en lugar de hacer ViewData["clave"] hacemos ViewBag.clave. Y para recuperarlos desde una vista? Pues igual que antes, podemos usar la propiedad ViewBag:
<h2>Index2</h2> Mi nombre es @ViewBag.Nombre y puedes seguirme en <a href="http://twitter.com/@ViewBag.Twitter">Twitter</a>. <br /> Dado de alta en: @ViewBag.FechaAlta.ToLongDateString()

Aqu podemos ver la gran ventaja de ViewBag respecto ViewData: no es necesario usar casting. Fijaos que para usar ToLongDateString() no hemos tenido necesidad de convertir el resultado devuelto por ViewBag.FechaAlta a DateTime. Esa es la gran ventaja de ViewBag respecto a ViewData y es por eso que, personalmente, os recomiendo usar ViewBag en lugar de ViewData (de hecho ViewData se mantiene por compatibilidad con las versiones anteriores del framework de ASP.NET MVC). Otra ventaja es que no usamos cadenas sino propiedades para acceder a los elementos, pero ojo, que el compilador no puede ayudaros si accedis a una clave (propiedad) que no existe (al ser las propiedades dinmicas).

Tercer mtodo: Model (tambin conocido como ViewModel)


El tercer mtodo para pasar informacin de una accin de un controlador a una vista, es usando la propiedad Model. La propiedad Model no funciona como las anteriores, sino que lo que se pasa es un objeto, que se manda de la accin hacia la vista. A diferencia de ViewData y ViewBag que existen tanto en el controlador como en la vista, el controlador no tiene una propiedad Model. En su lugar se usa una sobrecarga del mtodo View() y se manda el objeto como parmetro:
public { public public public } class Usuario string Nombre { get; set; } string Twitter { get; set; } DateTime Alta { get; set; }

public class HomeController : Controller { public ActionResult Index3() { Usuario data = new Usuario(); data.Nombre = "Eduard Toms"; data.Twitter = "eiximenis"; data.Alta = new DateTime(2008, 12, 10); return View(data); } }

Manual del framework ASP.NET MVC: www.desarrolloweb.com/manuales/framework-asp-net-mvc.html


Los manuales de DesarrolloWeb.com tienen el copyright de sus autores. No reproducir sin autorizacin.

11

Tu mejor ayuda para aprender a hacer webs www.desarrolloweb.com Notemos las diferencias: El controlador crea un objeto de la clase Usuario y manda ese objeto a la vista, pasndolo como parmetro a la funcin View. Y desde la vista? Pues usamos la propiedad Model para acceder a dicho objeto:
@model MvcHelloWorld.Controllers.Usuario <h2>Index3</h2> Mi nombre es @Model.Nombre y puedes seguirme en <a href="http://twitter.com/@Model.Twitter">Twitter</a>. <br /> Dado de alta en: @Model.Alta.ToLongDateString()

Fijaos que ahora usamos Model para acceder a los datos, en lugar de ViewData o ViewBag. Y una cosa importante: fijmonos en la primera lnea, que empieza con @model. Esa lnea le indica al framework de que tipo es el objeto que la vista recibe del controlador (es decir, de que tipo es la propiedad Model). Por supuesto este tipo debe coincidir con el objeto que se pasa como parmetro a la funcin View en la accin del controlador. Una nota: El uso de @model es opcional, si no lo ponemos, nuestra vista puede seguir usando la propiedad Model, pero en este caso es de tipo dynamic. Eso tiene sus ventajas y sus inconvenientes (volveremos sobre ello en posteriores artculos). Las vistas que declaran @model, se llaman vistas fuertemente tipadas. Usar vistas fuertemente tipadas tiene una ventaja que es que al saber Visual Studio cual es el tipo de la propiedad Model, nos puede proporcionar soporte de Intellisense. Usar este mecanismo es la manera preferida de pasar datos desde una accin a una vista (ya que en lugar de tener datos desperdigados en n claves los podemos tener organizados en una clase). A las clases que se pasan desde las acciones a las vistas (como nuestra clase Usuario) se les conoce tambin con el nombre de ViewModels (para distinguirlas de las clases que conforman el Modelo del patrn MVC, ya que los ViewModels lo nico que hacen es contener datos que mostrar una vista).

Una nota final


Al principio del artculo he comentado que veramos tres mtodos que en realidad eran dos. A que me refera? Pues bsicamente a que ViewBag y ViewData son dos maneras distintas para acceder al mismo conjunto de datos. Es decir, si establecemos el valor de ViewData["Nombre"] podemos leerlo con ViewBag.Nombre y viceversa. De ah que haya comentado que eran tres mtodos, que realmente eran dos. Para ms informacin os recomiendo el artculo de Jos M. Aguilar sobre el tema, que podis leer en: http://www.variablenotfound.com/2010/12/viewbag-en-aspnet-mvc-3.html Un saludo a todos! PD: Comentaros solamente que el cdigo fuente de todos los artculos de esta serie sobre ASP.NET MVC lo podris encontrar en: http://cid-6521c259e9b1bec6.office.live.com/browse.aspx/desarrolloweb-aspnetmvc
Artculo por

Eduard Toms

El motor de vistas Razor


Analizamos la sintaxis y sus consideraciones para el motor de vistas Razor en .NET. Desde su versin ASP.NET MVC ha tenido el concepto de motor de vistas (View Engine). A ver, recapitulemos: en ASP.NET MVC las vistas realizan tareas slo de presentacin. No contienen ningn tipo de lgica de negocio y no acceden a datos. Bsicamente se limitan a mostrar datos (en el artculo anterior vimos como pasar datos de los controladores a las vistas) y a solicitar datos nuevos al usuario. Si vienes del mundo de webforms, olvdate del concepto de Web Controls: no existen en ASP.NET MVC. No tenemos drag and drop, no configuramos propiedades. Las vistas son bsicamente HTML. Y lo que no es HTML son pequeas porciones de cdigo de servidor destinadas a terminar generando HTML para mostrar informacin. El equipo que desarroll ASP.NET MVC tuvo la feliz idea de permitir separar la sintaxis de servidor usada, del framework de ASP.NET MVC. El resultado? Lo que llamamos un motor de vistas de ASP.NET MVC. En las versiones 1 y 2, el framework viene con un nico motor de vistas, el llamado motor ASPX, que usa los clsicos archivos .aspx como vistas de ASP.NET MVC. Pero ojo! Aunque estemos utilizando archivos .aspx, no son webforms (los webcontrols no funcionan, no

Manual del framework ASP.NET MVC: www.desarrolloweb.com/manuales/framework-asp-net-mvc.html


Los manuales de DesarrolloWeb.com tienen el copyright de sus autores. No reproducir sin autorizacin.

12

Tu mejor ayuda para aprender a hacer webs www.desarrolloweb.com tenemos viewstate ni el ciclo de vida de webforms y adems es que son vistas de MVC, por lo que slo deben hacer tareas de presentacin). La sintaxis que usa el motor ASPX es un poco eso que los anglosajones llaman verbose, es decir que se debe escribir mucho para ciertas tareas. As, imaginad una pgina que tuviese que mostrar una lista de elementos de la clase Usuario (la que usamos en el captulo anterior). El cdigo, usando el motor de vistas ASPX queda as:
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<IEnumerable<MvcHelloWorld.Controllers.Usuario>>" %> <asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server"> DemoAspx </asp:Content> <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server"> <h2>DemoAspx</h2> <table> <% foreach (var item in Model) { %> <tr> <td> <%: item.Nombre %> </td> <td> <%: item.Twitter %> </td> <td> <%: String.Format("{0:g}", item.Alta) %> </td> </tr> <% } %> </table> </asp:Content>

Fijaos en la cantidad de veces que debe usarse el tag <% y su parejo %> para indicar dnde empieza y termina el cdigo de servidor. Rpidamente empezaron a surgir motores de vistas alternativos, realizados por la comunidad, con la intencin de tener sintaxis ms claras para nuestras vistas. Algunos ejemplos son Nhaml y Spark. Finalmente la versin 3 de ASP.NET MVC vino acompaada de un nuevo motor de vistas, llamado Razor. Eso s, el motor ASPX puede seguir siendo usado en ASP.NET MVC3, pero honestamente no hay ninguna razn para hacerlo (salvo en casos de migraciones, por supuesto): Razor es ms claro, sencillo e intuitivo.

Sintaxis de Razor
Lo que ms choca de Razor es que, a diferencia del motor ASPX donde tenemos el tag que inicia el cdigo de servidor y el que lo termina, slo hay tag para iniciar cdigo de servidor. El motor Razor es lo suficientemente inteligente para saber cundo termina el cdigo de servidor, sin necesidad de que lo explicitemos. Veamos la misma vista de antes, pero ahora usando Razor:
@model IEnumerable<MvcHelloWorld.Controllers.Usuario> @{ ViewBag.Title = "DemoRazor"; } <h2>DemoRazor</h2> @foreach (var item in Model) { <tr> <td> @item.Nombre </td> <td> @item.Twitter </td> <td> @String.Format("{0:g}", item.Alta) </td> </tr> } </table>

Las diferencias saltan a la vista, no? En Razor el smbolo de la arroba (@) marca el inicio de cdigo de servidor. Y como

Manual del framework ASP.NET MVC: www.desarrolloweb.com/manuales/framework-asp-net-mvc.html


Los manuales de DesarrolloWeb.com tienen el copyright de sus autores. No reproducir sin autorizacin.

13

Tu mejor ayuda para aprender a hacer webs www.desarrolloweb.com comentaba antes, no hay smbolo para indicar que se termina el cdigo de servidor: el motor Razor deduce cuando termina en base al contexto. Fijaos que para mostrar una variable de servidor (item.Nombre p.ej.) simplemente la precedemos de una @. Fijaos tambin que la llave de cierre del foreach no debe ser precedida de ninguna arroba, Razor ya sabe que esa llave es de servidor y cierra el foreach abierto. El uso de la @ funciona de dos maneras bsicas: 1. @expresin: Renderiza la expresin en el navegador. As @item.Nombre muestra el valor de tem.Nombre. Es decir @expresin equivale a <%: expresin %> 2. @{ cdigo }: Permite ejecutar un cdigo que no genera salida HTML. Es decir @{cdigo} equivale a <% Cdigo %>

Consideraciones a la sintaxis
Expresiones compejas Como hemos visto el motor Razor interpreta cuando empieza y cuando termina el cdigo de servidor. Pero no siempre lo consigue adecuadamente. P.ej, el siguiente cdigo Razor: @{ int a = 10; int b = 3; } El valor de 10 - 3 es: @a-b Genera el siguiente HTML: El valor de 10 - 3 es: 10-b Es decir Razor ha interpretado que el cdigo de servidor terminaba al encontrar el smbolo de resta. En este caso, esa presuncin es totalmente errnea, pero por suerte podemos usar los parntesis para que haya slo una expresin detrs de la arroba: El valor de 10 - 3 es: @(a-b) Con ese cdigo la vista mostrar el valor correcto (7). Recordad la clave: el motor Razor espera una y slo una expresin detrs de la @. Por eso debemos usar los parntesis. "Romper" el cdigo de servidor A veces la problemtica es justo la contraria de la que hemos visto con las expresiones complejas: a veces hay cdigo que Razor interpreta que es de servidor pero realmente parte de ese cdigo es HTML que debe enviarse al cliente. Veamos un ejemplo:
@for (int i = 0; i < 10; i++) { El valor de i es: @i <br /> }

A priori podramos esperar que este cdigo generara 10 lneas de cdigo HTML. Pero el resultado es un error de compilacin. La razn es que Razor interpreta que la lnea "El valor de i es: @i" es cdigo de servidor. Para "romper" este cdigo de servidor y que Razor "sepa" que realmente esto es cdigo que debe enviarse tal cual al cliente, tenemos dos opciones: 1. Intercalar una etiqueta HTML. Al intercalar una etiqueta HTML Razor "se da cuenta" que all empieza un cdigo de cliente:
@for (int i = 0; i < 10; i++) { <span>El valor de i es:</span> @i <br /> }

2. Usar la construccin @: que indica explcitamente a Razor que lo que sigue es cdigo de cliente:
@for (int i = 0; i < 10; i++) { @:El valor de i es: @i <br /> }

Manual del framework ASP.NET MVC: www.desarrolloweb.com/manuales/framework-asp-net-mvc.html


Los manuales de DesarrolloWeb.com tienen el copyright de sus autores. No reproducir sin autorizacin.

14

Tu mejor ayuda para aprender a hacer webs www.desarrolloweb.com La diferencia es que en el primer caso las etiquetas se envan al navegadaor, mientras que en el segundo caso no.

Consideraciones en correos electrnicos


La gente que ha desarrollado el motor Razor ha tenido en cuenta una excepcin para los correos electrnicos. Es decir, Razor es de nuevo, lo suficientemente inteligente para saber que una expresin es un correo electrnico. As pues el siguiente cdigo no da error y enva el HTML esperado al cliente:
Enviame un mail: a usuario@servidor.com

En este caso Razor interpreta que se trata de un correo electrnico, por lo que no trata la @ como inicio de cdigo de servidor. Este comportamiento a veces tampoco se desa. P.ej, imaginad lo siguiente:
<div id="div_@Model.Index">Div usado</div>

Estoy asumiendo que el ViewModel que recibe la vista tiene una propiedad llamada Index. Supongamos que dicha propiedad (Model.Index) vale 10. La verdad es que uno pensara que eso generara el cdigo HTML:
<div id="div_10">Div usado</div>

Pero el resultado es bien distinto. El cdigo HTML generado es:


<div id="div_@Model.Index">Div usado</div>

Es decir, Razor no ha interpretado la @ como inicio de cdigo de servidor, y eso es porque ha aplicado la excepcin de correo electrnico. La solucin pasa por usar los parntesis:
<div id="div_@(Model.Index)">Div usado</div>

Ahora Razor sabe que Model.Index es cdigo de servidor y lo evaluar, generando el HTML que estbamos esperando. A veces Razor falla incluso ms espectacularmente. Dado el siguiente cdigo:
@for (int i = 0; i <= 1; i++) { <div id="div_@i">Div @i</div> }

En base a lo que hemos visto podramos esperar que generase el siguiente HTML:
<div id="div_@i">Div 0</div> <div id="div_@i">Div 1</div>

Pues no! Este cdigo hace que el motor de Razor de un error (The for block is missing a closing "}" character. Make sure you have a matching "}" character for all the "{" characters within this block, and that none of the "}" characters are being interpreted as markup). Por supuesto, la solucin para generar el HTML que queremos pasa por usar el parntesis igual que antes:
@for (int i = 0; i <= 1; i++) { <div id="div_@(i)">Div @i</div> }

Genera el HTML esperado:


<div id="div_0">Div 0</div> <div id="div_1">Div 1</div>

Escapar la arroba A veces es necesario indicarle a Razor que una arroba es eso una simple arroba y que no haga nada especfico. Que no asuma nada, que no piense nada, que simplemente enve una @ al cliente. Un ejemplo? El siguiente cdigo:
<style> @@media screen { body { font-size: 13px;} } </style>

Si no usramos la doble arroba (@@), Razor nos generara un error, ya que @media lo interpreta como "enviar el contenido

Manual del framework ASP.NET MVC: www.desarrolloweb.com/manuales/framework-asp-net-mvc.html


Los manuales de DesarrolloWeb.com tienen el copyright de sus autores. No reproducir sin autorizacin.

15

Tu mejor ayuda para aprender a hacer webs www.desarrolloweb.com de la variable media al cliente". En este caso al usar @@ Razor simplemente sabe que debe enviar una @ al cliente y lo que el navegador recibe es:
<style> @media screen { body { font-size: 13px;} } </style>

Conclusiones
Hemos visto la sintxis bsica del motor de vistas Razor, y las principales consideraciones que debemos tener presentes. No hemos visto las capacidades adicionales de dicho motor de vistas como layouts, templates y regiones que iremos viendo en captulos posteriores. Para finalizar una cosilla: Ambos motores de vistas (ASPX y Razor) se pueden usar en MVC3 de forma simultnea. El motor de ASP.NET MVC intentar encontrar primero una vista .aspx y si no la encuentra buscar una vista Razor (.cshtml, aunque tambin puede ser .vbhtml si usamos Visual Basic.NET en lugar de C#). Aunque por supuesto este comportamiento puede ser modificado. Un saludo a todos!
Artculo por

Eduard Toms

Tabla de rutas Parte 1


La tabla de rutas en el framework ASP .NET MVC sirve para mapear las URLs de la aplicacin a sus correspondientes controladores y acciones dentro de ellos. En estos primeros cuatro captulos de esta serie sobre ASP.NET MVC hemos visto los aspectos fundamentales del framework: controladores, acciones y vistas. En el captulo dos, vimos que cada peticin del navegador debe ser enrutada a una accin de un controlador. Dijimos tambin que por defecto se sigue la convencin de que las URLs estn en forma http://servidor/controlador/accion. Lo que mucha gente no sabe es que eso no es realmente una convencin del framework de ASP.NET MVC ni mucho menos una obligacin. Que las URLs sigan por defecto esta forma se debe, ni ms ni menos, al cdigo que nos genera por defecto Visual Studio cuando creamos un proyecto ASP.NET MVC. La responsable de decidir qu accin de qu controlador se encarga de procesar cada peticin es la tabla de rutas y es de lo que vamos a hablar hoy. Hablando rpidamente podramos decir que la tabla de rutas es la responsable de mapear cada URL a una accin de un controlador. La frase puede parecer balad, pero no lo es en absoluto. Hay dos aspectos clave a tener en cuenta: 1. Cada URL debe ser mapeada a una accin de un controlador en concreto. 2. Para mapear una peticin del navegador a una accin de un controlador se usa slo la URL. Repito: slo la URL. Hablando en propiedad, la frase anterior no es del todo precisa. Lo que la tabla de rutas realmente hace es determinar qu valores de ruta (route values) se rellenan a partir de la URL. Lo que nos lleva a preguntarnos, que son los valores de ruta.

Valores de ruta (route values)


Los valores de ruta no son ms que un conjunto de valores (parmetros si prefers) cuyo valor se extrae a partir de la peticin que realiza el navegador, concretamente a partir de la URL. Puede haber todos los valores de ruta que se quiera, pero hay dos que deben ser establecidos siempre por cada URL: 1. controller: Debe contener el nombre del controlador que gestionar la peticin 2. action: Debe contener el nombre de la accin que gestionar la peticin

Manual del framework ASP.NET MVC: www.desarrolloweb.com/manuales/framework-asp-net-mvc.html


Los manuales de DesarrolloWeb.com tienen el copyright de sus autores. No reproducir sin autorizacin.

16

Tu mejor ayuda para aprender a hacer webs www.desarrolloweb.com Esos dos valores los espera el framework siempre, para as poder enrutar dicha peticin hacia una accin de un controlador. Pero al margen de esos dos, pueden existir otros valores de ruta. Y qu hace el framework con el resto de valores de ruta? Pues los guarda y los enva a la accin que gestiona la peticin. La tabla de rutas es pues la responsable de, decidir, por cada URL, que valores de ruta, y con qu valor real, se rellenan. Recordad que controller y action son obligatorios y que son usados por el framework para, precisamente, decidir qu accin de qu controlador gestiona la peticin, de ah que se diga comnmente, que la tabla de rutas mapea URLs a acciones, aunque como hemos visto, realmente hace algo ms.

Configuracin de la tabla de rutas


La tabla de rutas no tiene valores por defecto. Es decir, inicialmente est vaca y eso significa que no hay ninguna peticin que se pueda enrutar. Es el propio Visual Studio, quien nos genera cdigo para configurar la tabla de rutas, con unos valores iniciales. Y esos valores son los que hacen que las URLs tengan la forma conocida de http://servidor/controlador/accion. Si abrs Visual Studio y creis un proyecto ASP.NET MVC nuevo (incluso si elegs la opcin de Empty), veris el siguiente cdigo en el archivo Global.asax.cs:
public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( "Default", // Route name "{controller}/{action}/{id}", // URL with parameters new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults ); }

Este cdigo es el que configura la tabla de rutas. El parmetro routes que recibe este mtodo es la propia tabla de rutas, que est en la propiedad esttica Routes de la clase RouteTable. Analicemos este cdigo, y empecemos no por la primera lnea, sino por la segunda: la que llama al mtodo MapRoute. Este mtodo (que es realmente un mtodo de extensin, aunque esto no sea relevante) nos permite aadir una nueva entrada a la tabla de rutas de forma sumamente sencilla. Est sobrecargado pero en este cdigo los parmetros que recibe son: 1. El nombre de la ruta (un identificador de la ruta). En este caso la ruta se llama Default 2. Las URLs que mapea esta ruta 3. Los valores por defecto de los valores de ruta, en caso de no ser encontrados en la URL.

Patrones de URLs
Centrmonos un poco en segundo parmetro. Su valor es {controller}/{action}/{id}. Eso es simplemente el patrn que deben cumplir las URLs para ser procesadas por esta ruta. Lo que est entre llaves es el nombre del valor de ruta que se crea. As pues el patrn {controller}/{action}/{id} mapear cualquier URL que est en la forma http://servidor/xxx/yyy/zzz. Y adems asignar los siguientes valores de ruta: 1. controller = xxx 2. action = yyy 3. id = zzz Pero que pasa con una URL que no tenga el /zzz final? Que ocurre con una URL http://servidor/xxx/yyy? Pues en principio una URL de este tipo no sera procesada por este patrn (ya que el patrn pide explcitamente que haya {controller}/{action}/{id}. Pero, para evitar que la configuracin de la tabla de rutas costase horrores, existe el tercer parmetro: los valores por defecto.

Valores por defecto


El tercer parmetro de MapRoute son los valores por defecto de los valores de ruta. Es decir, si el valor de ruta no puede sacarse a partir del patrn de URL especificado, se asumir dicho valor. Se define como un objeto annimo cuyas propiedades tienen el nombre de los valores de ruta y el valor de dicha propiedad es el valor por defecto del valor de ruta. En nuestro caso est definido como:

Manual del framework ASP.NET MVC: www.desarrolloweb.com/manuales/framework-asp-net-mvc.html


Los manuales de DesarrolloWeb.com tienen el copyright de sus autores. No reproducir sin autorizacin.

17

Tu mejor ayuda para aprender a hacer webs www.desarrolloweb.com


new { controller = "Home", action = "Index", id = UrlParameter.Optional }

Por lo tanto tenemos que: El valor de ruta controller vale Home por defecto. El valor de ruta action vale Index por defecto El valor de ruta id es opcional. Es decir si no aparece no se crear (no existir). No es que valga null, 0, cadena vaca o cualquier otro valor vaco, no. Simplemente no se crear.

Visto esto, ahora podemos ver que: 1. http://servidor/Books/View/10 se procesar y los valores de ruta sern 1. controller = Books 2. action = View 3. id = 10 2. http://servidor/Books se procesar y los valores de ruta sern 1. controller = Books 2. action = Index (valor por defecto) 3. id = No existir el valor de ruta id 3. http://servidor se procesar y los valores de ruta sern 1. controller = Home (valor por defecto) 2. action = Index (valor por defecto) 3. id = No existir el valor de ruta id 4. http://servidor/Books/View/10/20 No ser procesada por la tabla de rutas. Esta URL no puede mapearse al patrn {controller}/{action}/{id} Si una URL no puede ser procesada por la tabla de rutas, el framework devuelve un error http 404 (pgina no encontrada).

Mltiples patrones
La tabla de rutas se llama precisamente tabla porque puede contener varias entradas (es decir, varios patrones de URL, con sus parmetros por defecto, etc). Para aadir ms entradas (rutas, cada entrada se conoce como ruta), lo ms sencillo es aadir llamadas a MapRoute. P.ej. si quisiramos procesar la URL anterior http://servidor/Books/View/10/20 podramos aadir una entrada adicional:
routes.MapRoute( "DosIds", // Route name "{controller}/{action}/{id}/{id2}" );

Ahora la URL http://servidor/Books/View/10/20 ya puede ser procesada, y ser procesada por esa entrada nueva en la tabla de rutas. Los valores de ruta creados sern: controller = Books action = View id = 10 id2 = 20

Un tema importante es que el orden de las rutaas en la tabla de rutas importa. Por cada URL, el framework evaluar las distintas entradas de la tabla de rutas, una a una, en el orden en que estas se encuentren y tan buen punto una URL pueda ser procesada, se eligir esa entrada de la tabla de rutas. P.ej. supongamos que queremos mapear las URLs de la forma http://servidor/Ver/Edu a la accin View del controlador Profile con un valor de ruta llamado user cuyo valor sea lo que hay despus de Ver (Edu en este caso). Eso lo podemos conseguir con una entrada en la tabla de rutas:
routes.MapRoute( "ViewProfile", // Nombre de la ruta "Ver/{author}", // URL with parameters new { controller = "Profile", action = "View" } );

Un detallito a tener en cuenta de esta nueva entrada es que dado que no hay lugar en el patrn de URL para los valores de ruta de controller y action, al ser esos obligatorios, deben especificarse como valores por defecto.

Manual del framework ASP.NET MVC: www.desarrolloweb.com/manuales/framework-asp-net-mvc.html


Los manuales de DesarrolloWeb.com tienen el copyright de sus autores. No reproducir sin autorizacin.

18

Tu mejor ayuda para aprender a hacer webs www.desarrolloweb.com Esta entrada mapea una URL del tipo: http://servidor/Ver/Edu con los valores de ruta: controller = Profile (valor por defecto) action = View (valor por defecto) author = Edu (sacado del patrn de la URL)

Pero, podis comprobar que si aads esa lnea despus del routes.MapRoute que ya haba, si entris una URL del tipo http://servidor/Ver/Edu el framework os devolver un 404, incluso aunque tengis el controlador Profile con una accin View definida. Por qu? Pues simplemente porque la tabla de rutas se evala en orden. Y puede mapear la primera entrada (la ruta llamada Default) una URL del tipo http://servidor/Ver/Edu? La respuesta es que s, y los valores de ruta quedan establecidos a: controller = Ver action = Edu id = No hay valor de ruta id (recordad que era opcional)

Por lo tanto, a no ser que tengis un controlador llamado Ver con una accin llamada Edu (cosa poco probable, no nos vamos a engaar :p) el framework os devolver un 404. Para que todo funcione, la entrada Default debe estar despus de la nueva entrada:
public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( "ViewProfile", // Nombre de la ruta "Ver/{author}", // URL with parameters new { controller = "Profile", action = "View" } ); routes.MapRoute( "Default", // Route name "{controller}/{action}/{id}", // URL with parameters new {controller = "Home", action = "Index", id = UrlParameter.Optional} // Parameter defaults ); }

Ignorar patrones de URL


A veces es necesario que ciertas peticiones con una determinada URL, no sean gestionadas por el framework de ASP.NET sino por el propio motor de ASP.NET o bien el propio IIS. Un ejemplo podra ser una peticin a una imagen. En este caso, no vamos a querer un controlador que nos devuelva la imagen, es mucho mejor dejar que sea el propio IIS quien lo haga (ser mucho ms eficiente). Por ello el framework permite definir rutas de exclusin, es decir rutas que si mapean una determinada URL, dicha peticin ser ignorada por ASP.NET MVC. Para crear esas rutas especiales, se usa el mtodo IgnoreRoute. Se le suele pasar un solo argumento, que es el patrn de URL a ignorar. Un ejemplo lo tenemos en el propio cdigo que genera Visual Studio:
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

Este patrn de URL se mapear a todas aquellas URLs que tengan la forma http://servidor/xxx.axd/yyy Dnde: 1. xxx es cualquier nombre 2. yyy es cualquier cosa, incluyendo barras separadoras (/). El hecho de que yyy pueda incluir barras separadoras es porque se usa la forma {*nombre_valor_ruta} (con un asterisco) que es lo que se conoce como catch-all y significa literalmente: captura todos los caracteres de la URL que vengan a partir de ahora. Es decir la URL http://servidor/trace.axd/foo/bar/baz ser enrutada por esta ruta. Al ser declarada con IgnoreRoute, lo que har es que dicha peticin sea ignorada por ASP.NET MVC y ser procesada por alguien ms (en este caso el propio motor de ASP.NET, pero eso ya depende de cada caso).

Manual del framework ASP.NET MVC: www.desarrolloweb.com/manuales/framework-asp-net-mvc.html


Los manuales de DesarrolloWeb.com tienen el copyright de sus autores. No reproducir sin autorizacin.

19

Tu mejor ayuda para aprender a hacer webs www.desarrolloweb.com En el siguiente artculo vamos a ver los valores de ruta y los controladores.
Artculo por

Eduard Toms

Tabla de rutas Parte 2


Segunda parte de las explicaciones relativas a la tabla de rutas de ASP .NET MVC, un componente bsico que podemos configurar para personalizar totalmente las URLs de las aplicaciones web.

Valores de ruta y controladores


Hemos visto que hay dos valores de ruta (controller y action) que deben ser establecidos a partir de cada URL. Pero qu ocurre con el resto de valores de ruta que establecemos? (como p.ej. el id o el author" de los ejemplos anteriores). Pues, simplemente, esos valores son pasados a los controladores, donde pueden ser consultados de varias formas, siendo una de las ms comunes que estn como parmetros en las acciones. P.ej. en el caso del valor de ruta author, la accin View del controlador Profile podra estar declarada tal y como sigue:
public class ProfileController : Controller { [ActionName("View")] public ActionResult Ver(string author) { return View(); } } Nota: En este caso usamos el atributo [ActionName] que permite indicar el nombre de la accin que implementa un mtodo en concreto. Si no se usa ese atributo el nombre de la accin es el mismo que el nombre del mtodo. En este caso debemos usarlo porque la accin se llama View, pero el nombre de mtodo View ya est definido dentro de la clase Controller (y se usa para devolver vistas).

Podemos ver como la accin View recibe el parmetro author", cuyo valor ser valor de ruta con el mismo nombre (autor). Es decir, en el caso de la URL http://servidor/Ver/Edu el valor del parmetro author ser precisamente Edu. En el caso de parmetros opcionales, la cosa es un peln ms delicada. Supongamos que tenemos la siguiente accin:
public class HomeController : Controller { public ActionResult Index(int i) { return View(); } }

Supongamos que esta accin se ha mapeado a partir de la entrada Default de la tabla de rutas. Si entramos una url del tipo http://servidor/Home/Index/10 no hay problema porque el valor de id es 10. Pero, en este caso id es un parmetro opcional, y que ocurre si entramos la URL http://servidor/Home/Index? Recordad que un parmetro opcional, si no aparece simplemente no se crea. No es que valga 0 o null. Es que no se crea. Por lo tanto si entramos una URL de tipo http://servidor/Home/Index recibiremos un error:

El error viene a decir que la accin espera un parmetro (id) pero que no hay valor de ruta del cual tomar ese parmetro. Si el parmetro aceptase null (es decir, fuese un valor por referencia como string) el framework asignara null a ese parmetro y no se quejara. Pero int no acepta null, as que el framework da ese error. Es normal, al principio, pensar que para solucionar esto bastara con aadir, un mtodo Index sin parmetros al controlador.

Manual del framework ASP.NET MVC: www.desarrolloweb.com/manuales/framework-asp-net-mvc.html


Los manuales de DesarrolloWeb.com tienen el copyright de sus autores. No reproducir sin autorizacin.

20

Tu mejor ayuda para aprender a hacer webs www.desarrolloweb.com Algo como:


public class HomeController : Controller { // URLs tipo /Home/Index/10 public ActionResult Index(int i) { return View(); } // URLs tipo /Home/Index public ActionResult Index() { return View(); } }

Pero si probamos esto, nos damos cuenta de que ahora nos aparece otro error distinto:

Adems ese error aparece indistintamente, ya sea que entremos http://servidor/Home/Index/10 (con id) o http://servidor/Home/Index (sin id). La razn de este error es muy simple: una misma accin slo puede ser implementada por un solo mtodo (hay una excepcin a este caso que es cuando se usan verbos http distintos, pero eso lo veremos en artculos posteriores). En este caso tenemos dos mtodos (Index() y Index(int)) que ambos implementan la accin Index. Y eso no est permitido. La solucin a todo ese lo pasa por hacer una de esas dos cosas: 1. Convertir el parmetro de la accin a algo que acepte nulls (p.ej. string o bien int?). 2. O modificar la tabla de rutas para que el parmetro en lugar de ser opcional, tenga un valor por defecto. Si optamos por el primer caso, la accin puede quedar como:
public class HomeController : Controller { public ActionResult Index(int? id) { return View(); } }

Ahora, la URL http://servidor/Home/Index se enruta a esta accin y como el valor de ruta id no existe, el mtodo de accin recibir un null. Por otro lado la URL http://servidor/Home/Index/10 se enruta a esta misma accin y el valor de ruta id valdr 10 (y ese ser el valor del parmetro que reciba el controlador). Si optamos por modificar la tabla de rutas, en lugar de declarar el valor de ruta id como opcional, dicho valor debe tener un valor por defecto:
routes.MapRoute( "Default", // Route name "{controller}/{action}/{id}", // URL with parameters new {controller = "Home", action = "Index", id = 0} // Parameter defaults );

Fijaos ahora que el valor por defecto del valor de ruta id es 0. Ahora la URL http://servidor/Home/Index se enruta a la accin con el valor de ruta id con valor 0. Y por su lado la URL http://servidor/Home/Index/20 se enruta a la misma accin pero con el valor de ruta id a 20. Debe notarse que en este caso no puede diferenciarse entre la url http://servidor/Home/Index y la url http://servidor/Home/Index/0 (ambas URLs tienen el valor de ruta id con valor 0). As terminamos este artculo dedicado a la tabla de rutas, uno de los componentes bsicos de ASP.NET MVC pero que muy poca gente le presta atencin al principio!

Manual del framework ASP.NET MVC: www.desarrolloweb.com/manuales/framework-asp-net-mvc.html


Los manuales de DesarrolloWeb.com tienen el copyright de sus autores. No reproducir sin autorizacin.

21

Tu mejor ayuda para aprender a hacer webs www.desarrolloweb.com

Artculo por

Eduard Toms

Usando querystring en ASP.NET MVC


En toda aplicacin web hay dos mecanismos bsicos que se usan para pasar informacin de cliente al servidor: usando la URL (lo que se conoce como querystring) o usando un formulario (lo que se conoce como POST). ASP.NET MVC tiene un soporte directo para usar la querystring: los parmetros que se pongan a la URL sern enviados como parmetros de la accin correspondiente. Es decir, si yo tengo la siguiente url: http://host/home/Index?p1=10&p2=no (y suponiendo la tabla de rutas por defecto), se invocar la accin Index de HomeController con dos parmetros p1 (con valor 10) y p2 con valor no. As en el controlador podramos tener definida la accin de la siguiente forma:
public ActionResult Index(int p1, string p2) { // Codigo... }

Los nombres de los parmetros deben coincidir con los nombres de los parmetros de la querystring. Bien, fijaos que dado que hemos declarado el parmetro p1 como int slo podemos pasar valores enteros, mientras que en el parmetro p2, podemos pasar cualquier cadena. Si pasamos una cadena en el parmetro p1, p.ej. la url http://host/home/index? p1=texto&p2=otrotexto el error que recibimos es el siguiente:

Lo que ha ocurrido es que ASP.NET MVC ha intentado convertir el valor de p1 (texto) a un entero. Al no poder hacerlo, internamente asigna null al valor del parmetro p1, pero luego cuando debe invocar el mtodo Index y pasarle un int se encuentra que int no acepta valores null. De aqu el error que recibimos. Como podramos evitar esto? Bueno una manera fcil y sencilla es usar int? (es decir Nullable) en lugar de int para declarar el tipo de p1:
public ActionResult Index(int? p1, string p2) { // Codigo }

Ahora si invocamos la url y el valor de p1 no es numrico, nos llegar null, mientras que si el valor de p1 es numrico recibiremos su valor. La regla es realmente muy simple: Si quieres que un parmetro de querystring sea opcional debes usar un tipo por referencia

Manual del framework ASP.NET MVC: www.desarrolloweb.com/manuales/framework-asp-net-mvc.html


Los manuales de DesarrolloWeb.com tienen el copyright de sus autores. No reproducir sin autorizacin.

22

Tu mejor ayuda para aprender a hacer webs www.desarrolloweb.com (es decir una clase como string o Nullable). Si usas un tipo por valor (como int o double) el parmetro no puede ser opcional y adems el valor que se entre en la URL debe ser convertible de cadena al tipo concreto que pongas en el controlador.

Generar URLs con querystrings desde las vistas


Uno de los errores ms frecuentes en ASP.NET MVC es tener cdigo en las vistas que sea parecido a este:
Pulsa <a href="/Home/View?pid=10">aqu</a> para ver los detalles

Este cdigo tiene dos errores fundamentales. 1. Est ignorando al tabla de rutas. Est generando las URLs usando la convencin de Controlador/Accin pero esta convencin es slo vlida si se usa la tabla de rutas estndar. En proyectos de tamao medio es normal tener una tabla de rutas que sea totalmente personalizada (esa es una de las gracias de ASP.NET MVC!) 2. Est pasando los parmetros siempre en querystring, ignorando los valores de ruta Para solucionar el primer punto, lo que debemos hacer es usar el Helper Url. Los Helpers son clases que nos proporcionan mecanismos de ayuda (de serie vienen algunos que iremos viendo y se pueden crear de propios), para ayudarnos con tareas repetitivas. Para generar una URL que respete la tabla de rutas debemos usar el mtodo Url.Action. Su firma bsica es Url.Action (accin, controlador). As el cdigo anterior lo podemos reescribir de la forma:
Pulsa <a href="@Url.Action("View","Home")?pid=10">aqu</a> para ver los detalles

Si ejecutamos eso y miramos el cdigo HTML veremos que es exactamente lo que habamos tecleado antes (debido a que usamos la tabla de rutas estndar). Pero si aado una entrada a la tabla de rutas, dejndola as:
routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( "Ver", "VerProducto", new {controller = "Home", action = "View"}); routes.MapRoute( "Default", // Route name "{controller}/{action}/{id}", // URL with parameters new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults );

Ahora la URL que se me genera usando Url.Action es la siguiente:


Pulsa <a href="/VerProducto?pid=10">aqu</a> para ver los detalles

As pues, siempre que necesitis obtener una URL desde una vista, usad Url.Action recordad que el formato real de las URLs depende de la tabla de rutas. Asumir que siempre estarn en la forma /controlador/accin es una muy mala prctica (y como deca antes, un error comn al principio).

Parmetros querystring y route values


Vamos a ver ahora que significa el segundo de los errores que cometamos (pasar los valores siempre en querystring ignorando los valores de ruta). Para evitar entrar demasiado en tecnicismos dir que ASP.NET MVC mezcla todos los parmetros que le llegan antes de pasarlos a los controladores. A un controlador le pueden llegar parmetros por tres formas bsicas (vale, eso no es del todo cierto, hay ms formas pero vamos a ignorarlas de momento): como parmetros de ruta, como querystring y como POST (de esos hablaremos en un artculo posterior). Los parmetros de ruta son los que colocamos en la URL separados por la barra, es decir: http://host/controlador/accion/10. En este caso 10 es el valor de un parmetro de ruta. De cul? Pues el nombre debe estar explicitado en la tabla de rutas. Vamos a suponer que usamos la tabla de rutas estndar. En este caso el nombre de dicho parmetro es id. Ahora yo os pregunto que ocurrira si usamos la URL http://host/controlador/accion/10?id=20 ? Fijaos que la cuestin no es balad: a nuestro controlador le estamos pasando: Un parmetro de ruta con valor 10 y que (gracias a la tabla de rutas) se llama id Un parmetro de querystring llamado id con valor 20.

Manual del framework ASP.NET MVC: www.desarrolloweb.com/manuales/framework-asp-net-mvc.html


Los manuales de DesarrolloWeb.com tienen el copyright de sus autores. No reproducir sin autorizacin.

23

Tu mejor ayuda para aprender a hacer webs www.desarrolloweb.com Ambos parmetros (de ruta y querystring) se mapean a parmetros de la accin del controlador. As pues que valor recibiremos en el parmetro id de nuestra accin? O bien ASP.NET MVC generar un error? Pues lo que recibiremos en nuestra accin ser el valor del parmetro de ruta (es decir 10, en lugar de 20):

Fijaos en la URL entrada (/Home/Index/10?id=20) y como el valor del parmetro id es 10 y no 20. Eso es debido a que comentbamos antes: ASP.NET MVC mezcla todos los parmetros que le llegan antes de enlazarlos con los controladores y lo hace segn una cierta prioridad. Y los parmetros de ruta (cuyo nombre se define en la tabla de rutas) tienen ms prioridad. Eso debera tenerlo en cuenta cuando genero URLs, es decir, en este caso debera generar URLs usando la convencin /controlador/accin/valor_id antes que /controlador/accin?id=valor_id Al final eso nos implica que no deberamos nunca generar las URLs con parmetros querystring aadidos a mano. Por suerte para nosotros el helper Url.Action que hemos visto antes viene de nuevo a nuestra ayuda. En una de sus sobrecargas Url.Action acepta un objeto annimo cuyas propiedades son los valores a mandar al controlador. Url.Action es lo suficientemente inteligente como para usar valores de ruta si estn definidos y querystring en caso de que no! As pues si tenemos la tabla de rutas estndar y tenemos las siguientes llamadas a Url.Action: Url 1: @Url.Action("Index", "Home", new { id = 20 }) Url 2: @Url.Action("Index", "Home", new { id = 20, otro_id=30}) Url 3: @Url.Action("Index", "Home", new {otro_id=30}) La respuesta generada por esa vista es la siguiente: Url 1: /Home/Index/20 Url 2: /Home/Index/20?otro_id=30 Url 3: /?otro_id=30 No es una maravilla? Url.Action sabe que id es un parmetro de ruta y nos lo coloca como tal. Y sabe que otro_id no lo es y nos lo coloca usando query_string. En este caso la accin en el controlador la tenemos definida:
public ActionResult Index(string id, string otro_id) { return View(); }

Fijaos como desde el controlador recibimos de igual manera parmetros de ruta que parmetros que vengan por querystring :) En el siguiente artculo del tutorial vamos a ver como mandar datos de formularios a las vistas, es decir cmo usar POST.
Artculo por

Eduard Toms

Uso de POST en ASP.NET MVC


Sin duda alguna de todos los mecanismos que hay para mandar informacin desde una vista hacia un

Manual del framework ASP.NET MVC: www.desarrolloweb.com/manuales/framework-asp-net-mvc.html


Los manuales de DesarrolloWeb.com tienen el copyright de sus autores. No reproducir sin autorizacin.

24

Tu mejor ayuda para aprender a hacer webs www.desarrolloweb.com controlador, el uso de POST es el ms comn. Dicho rpido y mal: el uso de POST equivale al uso de formularios HTML. Digo lo de mal porque ni los formularios son la nica manera de enviar datos va POST, ni todos los formularios se envan por POST, pero no nos vamos a centrar en estos detalles, ya que la mayora de formularios hoy en da se envan via POST. La principal diferencia entre enviar datos via POST o via GET (es decir usando la URL, ya sea a travs de querystring que vimos en el artculo anterior, o en valores de ruta) es que con POST los datos circulan en el cuerpo de la peticin y no son visibles en la URL.

Enviar datos a travs de un formulario


Hablar de datos enviados a travs de un formulario a un controlador implica presentar una caracterstica de ASP.NET MVC que se va a convertir en un gran aliado: el model binding. Por ese nombre nos referimos a la capacidad de ASP.NET MVC de construir objetos a partir de los datos que le lleguen en la peticin. Para ser honestos el model binding funciona con independencia de si los datos vienen de un formulario, en la querystring o por valores de ruta, pero va a ser cuando se mandan datos a travs de formularios que adquiere su mxima expresin. Pero vayamos por partes... Empecemos por una vista sencilla, que se mostrar en respuesta a la accin Nuevo del controlador Usuarios:
<h2>Nuevo usuario</h2> <form method="POST"> <label for="login">login:</label> <input type="text" name="login" /> <br /> <label for="password">clave:</label> <input type="text" name="password" /> <br /> <input type="submit" value="enviar"/> </form>

Esta vista crea un formulario que ser enviado por POST. El formulario contiene: Dos etiquetas con texto () Dos campos de texto (<input type=text>), uno que se llama login y otro llamado password (el valor de sus atributos name). Un botn para enviar el formulario

Si os fijis no hemos indicado a que URL debe enviarse el formulario. Eso se hace a travs del atributo action de la etiqueta <form>. Si no aparece, el formulario se mandar de vuelta a la misma URL a la que estamos. En el controlador (UsuariosController) metemos simplemente una accin que muestre la vista:
public ActionResult Nuevo() { return View(); }

Bien, si ahora con el navegador nos dirigimos a /Usuarios/Nuevo nos aparecer la vista con el formulario. Podemos rellenar datos y pulsar enviar. Al pulsar enviar simplemente se nos mostrar la vista (vaca) de nuevo. Esto ocurre porque al pulsar el botn de enviar datos se enva el formulario a la misma URL (/Usuarios/Nuevo) de la que venimos. Por lo tanto se invoca de nuevo la accin Nuevo del controlador Usuarios que lo nico que hace es mostrar la vista otra vez. Ahora bien, lo que nosotros queremos es que cuando se enve el formulario va POST podamos obtener los datos y hacer algo con ellos. En definitiva queremos hacer otra cosa que no sea mostrar la vista. La verdad es que suena un poco como si quisiramos otra accin distinta. Pero, si recordis en los inicios de este manual, dijimos que una accin slo poda estar implementada por un solo mtodo en el controlador. Bueno, la verdad es que... mentimos un poquillo. La realidad es que una accin puede estar implementada por un solo mtodo por cada verbo HTTP. Si no sabes lo que son los verbos HTTP no te preocupes mucho: es la manera tcnica de referirnos a GET y POST. As GET es un verbo HTTP y POST es otro. Hay ms, como HEAD, PUT y DELETE pero dado que no hay soporte en HTML para estos verbos no nos vamos a preocupar de ellos (eso no significa que ASP.NET MVC no los soporte, slo que no vamos a verlo aqu). Para nosotros slo van a existir GET y POST. Y volviendo a lo que decamos, eso significa que para la misma accin (por lo tanto, la misma

Manual del framework ASP.NET MVC: www.desarrolloweb.com/manuales/framework-asp-net-mvc.html


Los manuales de DesarrolloWeb.com tienen el copyright de sus autores. No reproducir sin autorizacin.

25

Tu mejor ayuda para aprender a hacer webs www.desarrolloweb.com URL) puedo tener dos mtodos en el controlador: uno que se invoque a travs de GET y otro que se invoque a travs de POST. As pues podemos aadir el siguiente mtodo a nuestro controlador:
[HttpPost] public ActionResult Nuevo(string login, string password) { // Codigo... }

Observad como el mtodo est decorado con [HttpPost]. Al aplicar este atributo al mtodo le estamos indicando a ASP.NET MVC que cuando se deba invocar la accin Nuevo del controlador Usuarios use este mtodo si la invocacin es va POST. Si la invocacin es va GET (p.ej. tecleando la URL en la barra de direcciones del navegador) se invocar el mtodo Nuevo que ya tenamos. Fijaos pues que tenemos una manera simple y elegante de separar nuestro cdigo en funcin del verbo HTTP que se use. Fijmonos ahora en los parmetros del mtodo Nuevo: dos parmetros cuyo nombre es el mismo que los nombres de los campos del formulario. Slo con esto le basta a ASP.NET MVC para enlazar los valores del formulario con los parmetros de la accin del controlador. Ahora bien, imagina que nuestro formulario en lugar de tener dos campos, tiene veinte... Te imaginas tener que poner veinte parmetros en la accin del controlador? Pues para evitar esto existe precisamente el model binding.

Model Binding
Llamamos model binding a la capacidad de ASP.NET MVC de crear objetos (de clases nuestras) a partir de los parmetros que vengan en la peticin. En nuestro caso a partir de los campos del formulario que enviamos. As podramos tener una clase Usuario tal y como sigue:
public class Usuario { public string login { get; set; } public string password { get; set; } }

Y sustituir los dos parmetros que tenamos en la accin Nuevo por un solo parmetro de tipo Usuario:
[HttpPost] public ActionResult Nuevo(Usuario usuario) { // Codigo... }

Y gracias al poder del model binding recibiremos un objeto usuario rellenado a partir de los datos del formulario. La nica condicin es que las propiedades del objeto se llamen igual que los campos del formulario. Llegados a este punto podramos validar los datos y si hay algn error, los podemos mandar de vuelta a la vista (junto con un mensaje explicativo del error):
[HttpPost] public ActionResult Nuevo(Usuario usuario) { if (string.IsNullOrEmpty(usuario.login) || string.IsNullOrEmpty(usuario.password)) { ViewBag.Error = "Login o password no pueden estar vacos"; return View(usuario); } // Damos de alta el usuario en la BBDD y redireccionamos return RedirectToAction("Home", "Index"); }

Si el campo de login o password se deja vacio, entonces aadimos un campo llamado Error en el ViewBag y devolvemos la vista, pasndole como datos el objeto usuario que hemos recibido. Si por otro lado la validacin es correcta redirigimos el usuario a la accin Index del controlador Home. Bien, ahora vayamos a por la vista: la idea es que si la vista recibe un objeto de tipo Usuario rellene los campos de texto con el valor de los campos de dicho usuario. De este modo al mandarle de vuelta el objeto desde el controlador, el usuario ver

Manual del framework ASP.NET MVC: www.desarrolloweb.com/manuales/framework-asp-net-mvc.html


Los manuales de DesarrolloWeb.com tienen el copyright de sus autores. No reproducir sin autorizacin.

26

Tu mejor ayuda para aprender a hacer webs www.desarrolloweb.com exactamente lo mismo que l ha enviado y slo deber corregir los errores que se le indiquen. El nuevo cdigo de la vista es:
@model MvcDatosPost.Models.Usuario <h2>Nuevo usuario</h2> @if (!string.IsNullOrEmpty(ViewBag.Error)) { <div class="error">@ViewBag.Error</div> } <form method="POST"> <label for="login" >login:</label> <input type="text" name="login" value="@(Model!=null ? Model.login : string.Empty)"/> <br /> <label for="password">clave:</label> <input type="text" name="password" /> <br /> <input type="submit" value="enviar"/> </form>

Lo que hemos aadido respecto a la vista original es que muestre un <div> con el error en caso de que este exista y establecer el valor del atributo value del campo login al valor del elemento recibido si existe. El valor del campo password no lo enlazamos porque, por norma general, cuando hay un error se obliga siempre a volver entrar el password. Y listos! Si el usuario enva un formulario con el campo login o password vacos, se le mostrar de nuevo los datos que haba entrada (salvo el password) junto con el mensaje de error. Sencillo, verdad? Pues bien, esa manera en que hemos hecho la validacin, y la forma en como hemos modificado la vista para mostrar los datos devueltos por el controlador, aunque funcionan no son las ideales. En los prximos artculos veremos dos maneras ms elegantes de hacerlo: por un lado la validacin mediante Data Annotations y por otro el uso de los helpers en las vistas... Un saludo!
Artculo por

Eduard Toms

Manual del framework ASP.NET MVC: www.desarrolloweb.com/manuales/framework-asp-net-mvc.html


Los manuales de DesarrolloWeb.com tienen el copyright de sus autores. No reproducir sin autorizacin.

27

Вам также может понравиться