Vous êtes sur la page 1sur 45

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

Key Consultant en Pasiona


http://geeks.ms/blogs/etomas
(12 captulos)

Miguel Angel Alvarez

Director de DesarrolloWeb.com y EscuelaIT


http://www.desarrolloweb.com
(1 captulo)

Manual del Framework ASP.NET MVC: 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-f48c4e95-a064-2a455a22c8f6&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.

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

Manual del Framework ASP.NET MVC: 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
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

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

Manual del Framework ASP.NET MVC: 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
"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.
Finalmente le damos a "Ok" y eso nos va a crear nuestro proyecto vaco.

Manual del Framework ASP.NET MVC: 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

Estructura de un proyecto ASP.NET MVC


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

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:

Manual del Framework ASP.NET MVC: 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

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
{
//
// 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: 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>

Y listos! Con esto ya tenemos nuestra aplicacin lista.


Para probarla basta ejecutarla (con F5) y comprobar los resultados:

Manual del Framework ASP.NET MVC: 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 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: 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);

Manual del Framework ASP.NET MVC: 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
Este valor es un DateTime, no obstante si desde la vista queremos llamar a los mtodos de DateTime (como
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";

Manual del Framework ASP.NET MVC: 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
data.Alta = new DateTime(2008, 12, 10);
return View(data);
}
}

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.

Manual del Framework ASP.NET MVC: 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
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 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>

Manual del Framework ASP.NET MVC: 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
@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 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 />

Manual del Framework ASP.NET MVC: 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
}

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 />
}

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

Manual del Framework ASP.NET MVC: 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
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 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.

Manual del Framework ASP.NET MVC: 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
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
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

Manual del Framework ASP.NET MVC: 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
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:
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 Indexpor 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

Manual del Framework ASP.NET MVC: 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

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.
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.

Manual del Framework ASP.NET MVC: 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
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).
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();
}

Manual del Framework ASP.NET MVC: 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
}

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. 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
lopasa 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).

Manual del Framework ASP.NET MVC: 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
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!
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:

Manual del Framework ASP.NET MVC: 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

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 (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

Manual del Framework ASP.NET MVC: 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
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.

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

Manual del Framework ASP.NET MVC: 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
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
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

Manual del Framework ASP.NET MVC: 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 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 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

Manual del Framework ASP.NET MVC: 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
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 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"/>

Manual del Framework ASP.NET MVC: 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
</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

Helpers para formularios


Los helpers nos van a permitir crear campos para crear un formulario de una manera muy cmoda.
En el artculo anterior vimos el uso de POST en ASP.NET MVC junto con las bases del Model Binding. En concreto la
norma ms importante que debemos recordad es que el atributo name del campo debe llamarse igual que la propiedad
que queremos enlazar. Por supuesto que el Model Binder admite enlazar parmetros complejos (una clase que tenga una
propiedad que sea una lista de objetos que a su vez tengan ms propiedades simples o complejas) y en este caso basta
que los atributos name de los campos del formulario sigan unas determinadas reglas. No vamos a entrar ms en detalle
porque, por suerte el framework nos ofrece una ayuda para no tener que recordar exactamente todas esas reglas: Los
helpers para formularios.
Los helpers nos van a permitir crear campos para crear un formulario de una manera muy cmoda y son sin duda alguna
la manera preferida de hacerlo.

Crear campos HTML


Lo primero que vamos a ver es como crear un campo HTML para editar (o mostrar) una propiedad especfica del
Viewmodel que recibe la vista. Supongamos que tenemos esa clase:
public
{
public
public
public
public
public
}

class Trabajador
string Nombre { get; set; }
string Apellido { get; set; }
DateTime FechaNacimiento { get; set; }
double Sueldo { get; set; }
bool EsFijo { get; set; }

Ahora vamos a crear una vista que muestre cuatro campos de texto (para nombre, apellido, fecha de nacimiento y
sueldo) y una casilla de verificacin para indicar si es fijo o no. Pero en lugar de crear los controles a mano (<input
type="xxx">) vamos a usar los helpers:
@using MvchelpersForms.Models
@model Trabajador
<form method="post">
Nombre: @Html.TextBoxFor(x=>x.Nombre) <br />
Apellido: @Html.TextBoxFor(x=>x.Apellido) <br />
Fecha Nacimiento: @Html.TextBoxFor(x=>x.FechaNacimiento) <br />
Sueldo: @Html.TextBoxFor(x => x.Sueldo) <br />

Manual del Framework ASP.NET MVC: manuales/framework-asp-net-mvc.html


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

27

Tu mejor ayuda para aprender a hacer webs


www.desarrolloweb.com
Es Fijo: @Html.CheckBoxFor(x=>x.EsFijo) <br />
<input type="submit" value="Enviar"/>
</form>

Estamos usando los helpers:

Html.TextBoxFor que muestra un campo de texto para la propiedad indicada


Html.CheckBoxFor que muestra una casilla de verificacin para la propiedad indicada

Fijaos en como se indica a cada helper para que propiedad debe renderizar el control:
@Html.TextBoxFor(x=>x.Nombre)

El parmetro en forma x=>x.Nombre es una expresin lambda. No es objetivo de este artculo entrar en las expresiones
lambda, as que nos vamos a limitar a indicar que en este caso se usan para indicar la propiedad. La ventaja de usar una
expresin lambda antes que una cadena (algo como TextBoxFor("Nombre")) es que las expresiones lambda son
evaluadas en tiempo de compilacin y no de ejecucin (si nos equivocamos en el nombre de la propiedad el cdigo no
compila). Esto requiere que la vista sea tipada con el tipo de ViewModel (fijaos en el uso de la directiva @model).
Bien, ahora veamos que cdigo fuente nos ha generado esta vista:
<form method="post">
Nombre: <input id="Nombre" name="Nombre" type="text" value="" /> <br />
Apellido: <input id="Apellido" name="Apellido" type="text" value="" /> <br />
Fecha Nacimiento: <input id="FechaNacimiento" name="FechaNacimiento" type="text" value="" /> <br />
Sueldo: <input id="Sueldo" name="Sueldo" type="text" value="" /> <br />
Es Fijo: <input id="EsFijo" name="EsFijo" type="checkbox" value="true" /><input name="EsFijo"
type="hidden" value="false" /> <br />
<input type="submit" value="Enviar"/>
</form>

La verdad es que no se diferencia mucho del cdigo que nosotros pondramos a mano (que vimos en el artculo
anterior). Lo que s os puede llamar la curiosidad es el campo hidden cuyo name es "EsFijo". Este campo existe para
bueno, para lidiar con el hecho de que una checkbox no marcada, no se enva. Es decir si tenemos el campo:
<input id="EsFijo" name="EsFijo" type="checkbox" value="true" />

Eso significa que si la checkbox est marcada se enviar el valor indicado en value (true), mientras que si la checkbox
no est marcada el navegador no enviar nada. Una checkbox no marcada es como si no existiese. Pero el Model
Binder de ASP.NET MVC esperar que haya un campo EsFijo para poder enlazarlo a la propiedad, de ah que se aada
este campo hidden con el mismo nombre y valor false. De este modo si la checkbox no est marcada el campo hidden se
enva y tiene el valor de false. Habras pensado t en eso? Esas son las ventajas de usar los helpers :)

Manual del Framework ASP.NET MVC: manuales/framework-asp-net-mvc.html


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

28

Tu mejor ayuda para aprender a hacer webs


www.desarrolloweb.com

Ventajas de usar los helpers


Pero todava hay ms, si mostris la vista en el navegador y sin introducir datos le dais a Enviar:

Exacto! Nos aparecen errores. En concreto el sistema nos muestra un error si FechaNacimiento o Sueldo estn vacos.
Y por qu esos dos campos y no los otros? Muy sencillo: porque esos dos campos estn declarados como DateTime y
double que son tipos por valor y por lo tanto nunca pueden valer null.
Ahora
probad de meter una cadena en el Sueldo:

Sigue dando error! Esto es porque la cadena dsddsd

no puede ser convertida en double, lo que genera un error.


Ahora bien, quiero dejar una cosa bien clara: El sistema siempre realiza esas validaciones con independencia de que
usemos los helpers o no. Pero estos ltimos estn preparados para mostrar el error (usar una clase CSS
especfica) si ese existe.
Ahora igual os surge la siguiente duda: Y si no uso los helpers como puedo saber si hay errores en un campo concreto?
Pues haciendo lo mismo que realmente hacen ellos: Acceder a la propiedad ModelState del ViewData que entre otras
cosas contiene los errores vinculados a una propiedad. Mirad como sera el cdigo si queremos generar el campo
Sueldo para que se comporte igual que usando el helper:
<input type="text" name="Sueldo" value="@(Model != null ? Model.Sueldo.ToString() : string.Empty)"
class="@(ViewData.ModelState.ContainsKey("Sueldo") && ViewData.ModelState["Sueldo"].Errors.Any() ?
"input-validation-error" : string.Empty )"
/>

Tenemos que realizar manualmente las dos tareas que el helper hace por nosotros:

Establecer la propiedad value al valor del ViewModel recibido si lo hubiese


Establecer la clase a input-validation-error en caso de haber un error vinculado en el campo que estamos

Manual del Framework ASP.NET MVC: manuales/framework-asp-net-mvc.html


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

29

Tu mejor ayuda para aprender a hacer webs


www.desarrolloweb.com
mostrando.
As pues, los helpers no son imprescindibles. Pero s que son muy cmodos y la manera recomendable de construir
formularios en ASP.NET MVC.
Hemos visto TextBoxFor y CheckBoxFor pero hay un helper por cada control HTML que habitualmente usamos en
formularios, as tenemos Html.TextAreaFor, Html.LabelFor, Html.DropDownListFor, etc
Os muestro el uso de Html.LabelFor porque es otro que se usa muchsimo. Ese genera un campo vinculado a una
propiedad. As si tenemos:
@Html.LabelFor(x=>x.Nombre) @Html.TextBoxFor(x=>x.Nombre) <br />

Nos genera el cdigo HTML:


<label for="Nombre">Nombre</label> <input id="Nombre" name="Nombre" type="text" value="" /> <br />

La etiqueta <label> se renderiza como texto plano. La ventaja de usarla es que al pulsar sobre la label el navegador da el
foco al control indicado en el atributo for (en ese caso el textbox de al lado).

Personalizacin de los helpers


Si a un helper slo le puedo pasar una expresin lambda que indica la propiedad para la cual debe renderizar un
determinado control HTML, como puedo personalizarlos? Por personalizarlos me refiero a poder aadir atributos
HTML adicionales como style o cualquier otro.
Pues bien, muchos de los helpers tienen una sobrecarga donde admiten un objeto annimo cuyas propiedades sern
mapeadas a atributos HTML al generar el cdigo. As pues el siguiente cdigo en la vista:
@Html.LabelFor(x => x.Nombre) @Html.TextBoxFor(x => x.Nombre, new { style = "border-color: blue",
size = "30" })

Genera el siguiente cdigo HTML:


<input id="Nombre" name="Nombre" size="30" style="border-color: blue" type="text" value="" />

Helpers "inteligentes"
Con los helpers que hemos visto hasta ahora es nuestra responsabilidad la de decidir qu control HTML mapeamos a
cada propiedad (un textbox, una checkbox, etc). Pero ASP.NET MVC incorpora dos helpers, llammosles "inteligentes"
que son capaces de determinar cul es el mejor control para visualizar o editar una propiedad concreta.
Esos dos helpers son:

HtmlDisplayFor: Renderiza el HTML necesario para visualizar una propiedad (sin poder ser editada)
HtmlEditorFor: Renderiza el HTML necesario para poder editar una propiedad.

Esos helpers son extraordinariamente potentes (tanto que van a tener un artculo para ellos solos) as que por ahora
vamos a ver solo su uso:
@using MvcHelpersForms.Models
@model Trabajador
<form method="post">
@Html.LabelFor(x => x.Nombre) @Html.EditorFor(x => x.Nombre)
<br />
Apellido: @Html.EditorFor(x => x.Apellido)
<br />
Fecha Nacimiento: @Html.EditorFor(x => x.FechaNacimiento)
<br />
Sueldo: @Html.EditorFor(x => x.Sueldo) <br />
Es Fijo: @Html.EditorFor(x => x.EsFijo)
<br />
<input type="submit" value="Enviar" />
</form>

Fijaos que ahora usamos solamente Html.EditorFor. El cdigo HTML generado ahora es:

Manual del Framework ASP.NET MVC: manuales/framework-asp-net-mvc.html


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

30

Tu mejor ayuda para aprender a hacer webs


www.desarrolloweb.com
<form method="post">
<label for="Nombre">Nombre</label> <input class="text-box single-line" id="Nombre" name="Nombre"
type="text" value="" />
<br />
Apellido: <input class="text-box single-line" id="Apellido" name="Apellido" type="text" value="" />
<br />
Fecha Nacimiento: <input class="text-box single-line" id="FechaNacimiento" name="FechaNacimiento"
type="text" value="" />
<br />
Sueldo: <input class="text-box single-line" id="Sueldo" name="Sueldo" type="text" value="" /> <br />
Es Fijo: <input class="check-box" id="EsFijo" name="EsFijo" type="checkbox" value="true" /><input
name="EsFijo" type="hidden" value="false" />
<br />
<input type="submit" value="Enviar" />
</form>

Este cdigo es casi idntico al que tenamos antes. Html.EditorFor renderiza un cuadro de texto para cada propiedad a
excepcin de la booleana para la cual renderiza una casilla de verificacin.
La pregunta evidente es: Si existe EditorFor para que usar el resto de helpers? Pues bien, cuando queris vosotros
decidir cul es el control HTML se usa para visualizar o mostrar una propiedad podis usar los helpers que vimos antes.
Cuando queris que sea el sistema usad EditorFor (o DisplayFor si estis realizando una vista que no permita editar).
Como ya os he avanzado antes EditorFor y DisplayFor son extraordinariamente potentes y con ellos se pueden hacer
autnticas maravillas, pero eso lo veremos en un artculo prximo.

El helper BeginForm
Bueno, ya que hablamos de helpers para generar formularios este es un buen momento para introducir el helper
BeginForm. Este helper lo que genera es
el tag <form>. Bueno, de hecho el tag <form> y su parejo </form>. Es por ello
que ese helper se "usa" de una forma un poco
distinta:
@using (Html.BeginForm()) {
<!-- Codigo del formulario -->
}

El cdigo que genera el formulario se incluye dentro de las llaves de apertura y cierre. Cuando se encuentre la llave de
cierra se generar el tag </form>. Al usar BeginForm() debemos tener un poco ms de cuidado con Razor. El siguiente
cdigo da error:
@Html.LabelFor(x => x.Nombre) @Html.EditorFor(x => x.Nombre)
<br />
Apellido: @Html.EditorFor(x => x.Apellido)
<br />
Fecha Nacimiento: @Html.EditorFor(x => x.FechaNacimiento)
<br />
Sueldo: @Html.EditorFor(x => x.Sueldo) <br />
Es Fijo: @Html.EditorFor(x => x.EsFijo)
<br />
<input type="submit" value="Enviar" />
}

La razn es que Razor interpreta que debe ejecutar el cdigo que se encuentra entre las llaves. Por supuesto, como ya
vimos, Razor es lo suficientemente inteligente para "ignorar" el cdigo HTML (como <br />) pero no el texto plano. Es
decir, Razor intentar ejecutar el cdigo Apellido: (o Es Fijo:) que un cdigo totalmente invlido en C#, de ah el error.
La solucin? La que vimos en el artculo que dedicamos a Razor, o bien usamos @: o bien usamos la etiqueta ficticia
<text> para indicarle a Razor que este texto plano es eso
texto plano, que debe mandar a la salida HTML sin ms:
@using (Html.BeginForm()) {
@Html.LabelFor(x => x.Nombre) @Html.EditorFor(x => x.Nombre)
<br />
@:Apellido: @Html.EditorFor(x => x.Apellido)
<br />
@:Fecha Nacimiento: @Html.EditorFor(x => x.FechaNacimiento)
<br />
<text>Sueldo:</text> @Html.EditorFor(x => x.Sueldo) <br />
<text>Es Fijo:</text> @Html.EditorFor(x => x.EsFijo)

Manual del Framework ASP.NET MVC: manuales/framework-asp-net-mvc.html


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

31

Tu mejor ayuda para aprender a hacer webs


www.desarrolloweb.com
<br />
<input type="submit" value="Enviar" />
}

Bueno! Suficiente por hoy, no? En este artculo hemos visto que son los helpers para formulario, como se usan y
cules son sus ventajas. En el siguiente artculo vamos a hablar de un tema importantsimo: las validaciones
Artculo por Eduard

Toms

Validaciones en ASP.NET MVC


Vemos qu son las validaciones en ASP .NET MVC y cmo utilizarlas de una forma efectiva.
En los dos artculos anteriores hemos visto como enviar datos a un controlador usando POST y como generar los
formularios usando los helpers. Introdujimos tambin el concepto de Model Binding (como ASP.NET MVC era capaz
de construir un objeto que reciba el controlador a partir de los datos de la peticin) y vimos como al usar los helpers
obtenamos gratuitamente algunas validaciones, p.ej. si declarbamos un campo como int, ASP.NET MVC comprobaba
que no entrsemos caracteres alfanumricos.
De hecho lo que vemos automticamente al usar los helpers no son validaciones, son errores. Si introducimos una
cadena alfanumrica en un campo que se ha declarado como int, cuando el Model Binder debe enlazar los datos genera
un error. Los errores que el Model Binder se encuentra al intentar enlazar los valores de la request con las propiedades
del viewmodel son guardados en el ModelState y pueden ser consultados desde el propio controlador y tambin desde la
vista. De hecho, como vimos en el artculo anterior, los helpers consultan el ModelState para usar una clase CSS
especfica en caso de que haya algn error asociado con el campo.
Intentar convertir una cadena alfanumrica en un int es pues un error, pero hay muchos ms casos en los que nos puede
interesar decirle al usuario que los datos entrados son incorrectos: campos obligatorios, cadenas con un determinado
formato (p.ej. un email) o dos campos que deben tener el mismo valor (p.ej. contrasea y comprobar contrasea). Son
esos casos cuando nos referimos a validaciones y es lo que vamos a tratar en nuestro artculo. Pero aunque nosotros
diferenciemos entre errores y validaciones ASP.NET MVC no lo hace: ambos son tratados igual, es decir ambos son
guardados en el ModelState. Pero antes de profundizar ms, veamos exactamente que es el ModelState.

ModelState o estado del modelo


El ModelState es un objeto, gestionado por el framework de ASP.NET MVC que indica cual es el estado del modelo. En
este contexto por modelo entendemos el objeto que recibe un controlador (lo que generalmente llamamos view model) y
por estado entendemos si es correcto o no. Correcto significa que los datos de la peticin eran vlidos y que el Model
Binder ha podido crear un objeto y rellenarlo. Incorrecto significa que haba algn dato de la peticin invlido, ya sea
por algn error (una cadena alfanumrica se ha intentado asignar a un int) o bien por alguna validacin fallida (una
cadena declarada como email no tena el formato correcto).
El ModelState es bsicamente un diccionario donde:
1. Las claves son los nombres de las propiedades de nuestro modelo (realmente son los nombres que usa el Model
Binder para enlazar las propiedades pero podemos asumir que coinciden).
2. Por cada clave hay el valor que el Model Binder ha asignado a esa clave y lo que ms nos importa: una
coleccin de los errores vinculados a esa clave si los hubiese. Y cuando aqu digo errores me refiero tanto a
errores como a validaciones fallidas.

Manual del Framework ASP.NET MVC: manuales/framework-asp-net-mvc.html


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

32

Tu mejor ayuda para aprender a hacer webs


www.desarrolloweb.com

Figura 1: ModelState con un error


La Figura 1 muestra la composicin del ModelState. La propiedad Keys contiene las claves (en este caso el viewmodel
que estbamos usando era una clase con una propiedad cadena Nombre y un int llamado Edad) y la propiedad Values
donde podemos ver, por cada clave, el valor que le ha sido asignado (Value) y la coleccin de errores (Errors).
El ModelState contiene una propiedad llamada IsValid que nos dice si el modelo es correcto, es decir si no hay errores.
Esa propiedad suele usarse de la siguiente forma:
[HttpPost]
public ActionResult Index(DemoModel data)
{
if (!ModelState.IsValid)
{
return View(data);
}
else
{
// Codigo normal
return View("ok");
}
}

Si el ModelState no es vlido significa que alguna entrada del usuario no es correcta, por lo tanto devolvemos de nuevo
la vista que contiene el formulario con los datos. Como vimos en el artculo anterior si usamos los helpers para crear el
formulario, esos mostrarn los errores (en color rojo con la CSS por defecto). Si el ModelState es vlido eso significa
que las entradas del usuario son correctas por lo que procedemos a realizar la accin que querramos.

Aadir nuestras validaciones


Bueno, hemos visto el mecanismo que usa el framework de MVC para indicarnos que hay algn error, el ModelState.
Ahora vamos a ver cmo podemos aadir nuestras validaciones. Aunque ASP.NET MVC es muy flexible en este punto,
vamos a ver la forma ms comn de hacerlo: usando DataAnnotations. En artculos posteriores veremos otras formas.
Para aadir validaciones usando DataAnnotations simplemente debemos decorar la propiedad que deseemos con alguno
de los atributos (algunos se encuentran en el namespace System.ComponentModel.DataAnnotations y otros en

Manual del Framework ASP.NET MVC: manuales/framework-asp-net-mvc.html


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

33

Tu mejor ayuda para aprender a hacer webs


www.desarrolloweb.com
System.Web.Mvc). P.ej. si tenemos el siguiente viewmodel:
public class DemoModel
{
public string Nombre { get; set; }
public int Edad { get; set; }
}

Si queremos que el Nombre sea obligatorio podemos decorarlo con [Required]:


public class DemoModel
{
[Required]
public string Nombre { get; set; }
public int Edad { get; set; }
}

Y listos! Solo con aadir el atributo Required, el framework sabe que el Nombre es requerido y si el usuario no lo entra
se mostrar un error:

Figura 2: El error generado por [Required]


Si comparas la Figura 2 con las capturas de pantalla del artculo anterior donde tambin se mostraban campos errneos,
vers una pequea diferencia: no solo se muestra el campo de rojo, sino que tambin hay un mensaje de error. Quin
aade ese mensaje de error? Pues un helper del que todava no habamos hablado: Html.ValidationMessageFor. Su uso
es como lo de los helpers para generar formularios: con una expresin lambda le indicamos la propiedad para la cual
queremos mostrar sus mensajes de error (si los hubiese). Ese es el cdigo completo de la vista que estamos usando:
@using (Html.BeginForm()) {
@Html.ValidationSummary(true)
<fieldset>
<legend>DemoModel</legend>
<div class="editor-label">
@Html.LabelFor(model => model.Nombre)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Nombre)
@Html.ValidationMessageFor(model => model.Nombre)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Edad)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Edad)
@Html.ValidationMessageFor(model => model.Edad)

Manual del Framework ASP.NET MVC: manuales/framework-asp-net-mvc.html


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

34

Tu mejor ayuda para aprender a hacer webs


www.desarrolloweb.com
</div>
<p>
<input type="submit" value="Create" />

</p>
</fieldset>

Otros atributos para validar


Hay varios atributos para distintas validaciones y todos se usan igual: decorando las propiedades. Si tu aplicacin exige
que sus usuarios tengan entre 18 y 65 aos, se puede usar Range:
public class DemoModel
{
[Required]
public string Nombre { get; set; }
[Range(18, 65)]
public int Edad { get; set; }
}

Ms atributos que existen:

StringLength: Para limitar el nmero de caracteres de un campo texto (p.ej. el password debe tener entre 6 y
15 caracteres).
Compare: Para que dos campos tengan el mismo valor (p.ej. password y repetir password)
RegularExpression: Para validar contra una expresin regular

Por supuesto existe la posibilidad de crearte tus propios atributos para validaciones propias
pero es eso es algo que
dejamos para un artculo posterior!

Personalizar las validaciones


Si ves la Figura 2 probablemente te preguntes si es posible modificar el color que se usa para mostrar los errores y el
mensaje que se muestra. La respuesta a ambas preguntas es s. Para modificar el color que se usa para mostrar los
errores basta con modificar la css. Los helpers usan la clase input-validation-error para indicar que el campo de
formulario est mostrando un error, as que su aspecto depende de cmo tengamos definida esa clase en la CSS. Por
otro lado el mensaje que vemos es el que genera el framework por defecto, pero podemos modificarlo por uno nuestro
usando la propiedad ErrorMessage que tienen todos los atributos de validacin:
public class DemoModel
{
[Required(ErrorMessage = "Nada de annimos. Aqu todo el mundo tiene un nombre!")]
public string Nombre { get; set; }
[Range(18,65, ErrorMessage = "Solo mayores de edad no jubilados")]
public int Edad { get; set; }
} IMAGEN

Manual del Framework ASP.NET MVC: manuales/framework-asp-net-mvc.html


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

35

Tu mejor ayuda para aprender a hacer webs


www.desarrolloweb.com
La Figura 3 muestra el resultado con esos mensajes de error:

Figura 3: Errores con mensajes personalizados

Sumario de validaciones fallidas


Hemos visto como el helper Html.ValidationMessageFor nos permite mostrar los mensajes de error vinculados a una
propiedad determinada. Pero a veces nos puede interesar mostrar un resumen con todos los mensajes de error, algo
como:

Figura 4: Sumario de validaciones fallidas


Pues bien, como no poda ser de otro modo existe un helper especfico para ello, llamado Html.ValidationSummary.
Este helper puede generar una lista (<li>) de elementos no ordenados (<ul>) con todas las validaciones que hayan
fallado. Su uso es tan simple como aadir dicho helper en el lugar donde queramos que aparezca dicha lista. Adems
admite varios parmetros para personalizarlo uno de los cuales permite aadir un ttulo que se mostrar antes de la lista:
@Html.ValidationSummary(true,"Hay varios errores:")

La cadena "Hay varios errores:" se mostrar antes de mostrar la lista. El primer parmetro por su parte indica si la lista
debe mostrar todos los errores (true) o solo aquellos que no estn vinculados a ninguna propiedad (false), es decir que
sean globales a todo el viewmodel (en efecto, es posible que haya errores en el ModelState que no estn asociados a
ninguna propiedad en concreto).

Manual del Framework ASP.NET MVC: manuales/framework-asp-net-mvc.html


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

36

Tu mejor ayuda para aprender a hacer webs


www.desarrolloweb.com

Validacin en cliente
Si usamos los atributos estndar (no creamos atributos propios) ya tenemos la validacin en cliente automtica. Es decir
al mismo tiempo que el usuario vaya tecleando los valores o cambie el foco ya ser irn mostrando los distintos errores
que haya. Si hay errores no podr enviar el formulario. Por supuesto la validacin en cliente no tiene nada que ver con
la seguridad, es un tema de usabilidad (darle feedback al usuario de forma ms rpida) as que el uso de validacin en
cliente no inhibe de realizarla en servidor. ASP.NET MVC la realiza siempre en servidor (y nosotros por nuestra parte
debemos comprobar siempre el valor de la propiedad IsValid del ModelState).
Si por alguna razn se desea desactivar la validacin en cliente en alguna vista, basta con llamar al mtodo
Html.EnableClientValidation con el parmetro a false:
@{ Html.EnableClientValidation(false); }
@using (Html.BeginForm())
{
// Codigo del form
}

Si creas atributos propios para validaciones personalizadas entontes es responsabilidad tuya asegurarte de que sean
compatibles para validar en cliente (tranquilo, veremos en artculos posteriores como hacerlo), pero los que vienen, lo
incluyen de serie.

Aadiendo errores propios al ModelState


Para terminar este artculo me gustara mostrar cmo podemos aadir errores propios en el ModelState. Esto puede ser
til en aquellos casos en que el cdigo de validacin no pueda ser incorporado en un atributo (porque no dependa
nicamente de los valores introducidos por el usuario sino que tambin dependa de factores externos). El
ModelStatetiene un mtodo llamado AddModelError que sirve exactamente para esto:
[HttpPost]
public ActionResult Index(DemoModel data)
{
if (ModelState.IsValid)
{
if (Manager.ExistePersona(data))
{
ModelState.AddModelError("", "Ya existe una persona con este nombre");
}
}
if (!ModelState.IsValid)
{

return View(data);

else

{
}

// Codigo normal
return View("ok");

En esta accin, si no hay errores en el modelo (es decir los datos introducidos por el usuario son correctos) el
controlador comprueba si ya existe una persona con esos datos (usando una clase inventada Manager), y si este es el
caso aade un error en el ModelState. En este momento ModelState.IsValid deja de ser true (puesto que ahora hay un
error). ModelState.AddModelError tiene dos parmetros:
1. A que propiedad se asigna el error. Si vale "" no se asigna a ninguna propiedad (se entiende que es un error
global que afecta a todo el viewmodel).
2. El mensaje de error asociado a dicho error.
Como podemos observar el que exista el error de "Ya existe una persona con este nombre" es algo que depende de los
datos introducidos pero sobretodo del estado del sistema (que exista o no ya una persona con este nombre). Estos tipos

Manual del Framework ASP.NET MVC: manuales/framework-asp-net-mvc.html


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

37

Tu mejor ayuda para aprender a hacer webs


www.desarrolloweb.com
de errores son los que suelen tratarse usando AddModelError.
Bueno, en este artculo nos hemos introducido en el modelo de validaciones de ASP.NET MVC. Hemos visto que es el
ModelState, como usar DataAnnotations y como aadir nuestros propios errores en el ModelState. Nos han quedado
varios aspectos que iremos tratando en futuros artculos como crear nuestros propios atributos de validacin y ver otros
mecanismos de validacin que no sea usando atributos.
Artculo por Eduard

Toms

Validaciones propias en ASP.NET MVC


Como crear validaciones propias en ASP.NET MVC tanto en servidor como en cliente.
En el artculo anterior vimos cmo usar Data Annotations para crear validaciones y como usar los helpers para mostrar
los mensajes de errores de las validaciones fallidas. Pero nos qued en el tintero ver cmo podemos crear nuestras
propias validaciones, si las que vienen de serie no nos sirven. Eso es lo que vamos a ver en este artculo.

Atributos de validacin propios


La manera en que podemos extender Data Annotations para validaciones personalizadas es creando un atributo de
validacin propio, que luego podremos aplicar a las propiedades de nuestro viewmodel que queramos validar.
Para crear un atributo de validacin propio basta con derivar de la clase ValidationAttribute y por lo general redefinir un
solo mtodo: IsValid. Dicho mtodo recibe un object con el valor a validar y debe devolver un booleano indicando si la
validacin ha sido correcta o no:
[AttributeUsage(AttributeTargets.Property)]
public class NumeroParAttribute : ValidationAttribute
{
public override bool IsValid(object value)
{
try
{
var number = Convert.ToInt32(value);
return number % 2 == 0;
}
catch (Exception)
{
return base.IsValid(value);
}
}
}

El atributo AtributeUsage se usa para indicarle a .NET donde es vlido aplicar este atributo (esto es siempre que se
creen atributos, ya sean para validaciones o para cualquier otra tarea). Aqu estamos indicando que este atributo se
aplica a propiedades, no a mtodos o a parmetros.
Una vez creado el atributo su uso es como cualquiera de los que vienen de serie: basta con aplicarlo a las propiedades
que deseemos validar.
public class DemoModel
{
[Range(1, 100, ErrorMessage = "Positivo menor que 100")]
[NumeroPar(ErrorMessage = "El nmero debe ser par.")]
public int ValorPar { get; set; }
}

Al derivar de la clase ValidationAttribute ya obtenemos la propiedad ErrorMessage que vimos en el artculo anterior y
que nos permite especificar un mensaje de error a mostrar en caso de que la validacin sea fallida. Tambin podemos
observar como a pesar de que la clase que hemos creado se llama NumeroParAttribute para aplicarla basta con decorar

Manual del Framework ASP.NET MVC: manuales/framework-asp-net-mvc.html


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

38

Tu mejor ayuda para aprender a hacer webs


www.desarrolloweb.com
la propiedad del viewmodel con [NumeroPar] (sin el sufijo Attribute).
Ahora podramos crear una vista para crear objetos DemoModel:
@using (Html.BeginForm()) {
@Html.ValidationSummary(true)
<fieldset>
<legend>DemoModel</legend>
<div class="editor-label">
@Html.LabelFor(model => model.ValorPar)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.ValorPar)
@Html.ValidationMessageFor(model => model.ValorPar)
</div>
<p>

<input type="submit" value="Create" />


</p>
</fieldset>
}

Y podramos comprobar como en efecto tan solo podemos entrar nmeros pares, comprendidos entre 1 y 100:

Figura 1: Validacin de nmero par fallida

Validacin propia en cliente


La diferencia del atributo NumeroPar con los que vienen de serie, como p.ej. Range es que los segundos validan en
cliente antes de que se enven los datos al servidor, mientras que los atributos propios tan solo se validan en servidor
(los atributos que vienen de serie tambin se validan en servidor, recordad que los datos deben validarse siempre en
servidor y que la validacin en cliente es solo por usabilidad y no por seguridad).
Por supuesto podemos aadir validacin en cliente para nuestros atributos. Llegados a este punto debo decir que el
mecanismo exacto depende de la librera de validacin que se use en cliente. Aqu vamos a ver cmo hacerlo usando
jQuery Validate que es la librera que se incluye por defecto en ASP.NET MVC. Para usar otras libreras de validacin
en cliente sera necesario realizar otros pasos.

Aadiendo el cdigo javascript


Lo primero que debemos hacer es crear el cdigo javascript que va a validar los datos. Si usamos jQuery Validate esto
equivale a aadir un validador nuevo. Para aadir un validador nuevo basta con darle un nombre y el mtodo javascript
a ejecutar:
$.validator.addMethod("numeropar", function (value, element, param) {
return value % 2 == 0;
});

Hemos aadido un validador llamado "numeropar" con la funcin de validacin asociada. Con esto ahora jQuery
Validate sabe que debe llamar a este mtodo javascript cuando se requiera usar el validador "numeropar".
El siguiente paso es informar a jQuery Validate cuando debe llamar a este validador "numeropar" que hemos aadido.
Para ello necesitaremos cdigo en cliente y en servidor.

Manual del Framework ASP.NET MVC: manuales/framework-asp-net-mvc.html


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

39

Tu mejor ayuda para aprender a hacer webs


www.desarrolloweb.com

La interfaz IClientValidatable
Empecemos por el cdigo de servidor: nuestro atributo de validacin debe implementar una interfaz llamada
IClientValidatable. Esta interfaz requiere que implementemos un solo mtodo llamado GetClientValidationRules, que
debe devolver una coleccin de objetos de la clase ModelClientValidationRule.
La clase ModelClientValidationRule contiene el nombre de la regla de validacin en cliente a aplicar y el mensaje de
error en caso de que dicha validacin falle. En nuestro caso una posible implementacin es:
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata,
ControllerContext context)
{
yield return new ModelClientValidationRule
{
ErrorMessage = this.ErrorMessage,
ValidationType = "numeropar"
};
}

Estamos devolviendo una coleccin con un solo elemento ModelClientValidationRule. El nombre de la regla de
validacin en cliente es numeropar y el mensaje de error es el mismo mensaje que se usa para la validacin en servidor.
Nota: Conoces la palabra clave yield? Esa palabra clave de C# permite devolver colecciones sin necesidad de crear una clase que
implemente la coleccin (usualmente una List<T>). Para ms informacin te remito al blog de Jos Manuel Alarcn donde lo cuenta de
forma fenomenal: http://www.jasoft.org/Blog/post/PermaLinkaspxguid=8dfbbe0c-7851-4cb8-8a49-150be21.aspx

Vale, hemos creado en cliente un validador llamado "numeropar" y hemos modificado nuestro atributo para indicar que
debe usarse la regla de validacin en cliente llamada "numeropar". Parece que todo debera funcionar
pero todava nos
queda un ltimo detalle.

Cdigo javascript no obtrusivo


Por defecto ASP.NET MVC3 no solo usa jQuery Validate para las validaciones sino que adems usa la versin
unobtrusive. No s si conoces el significado de cdigo javascript no obtrusivo (unobtrusive javascript) pero
resumindolo te puedo decir que se trata de que el cdigo javascript est totalmente separado de las etiquetas HTML.
Eso significa no ver ms los famosos onclick=""y similares. Las etiquetas HTML se mantienen totalmente limpias de
cdigo javascript y contienen tan solo atributos HTML estndar. El uso de javasctipt no obtrusivo se basa en una
caracterstica nueva de HTML5 (aunque es posible usar javascript no obtrusivo en versiones anteriores, aunque no de
forma tan elegante). Para ms informacin os remito a un post en mi blog donde comento ms en detalle que es y cmo
funciona el javascript no obtrusivo: http://geeks.ms/blogs/etomas/archive/2010/11/12/saca-tus-scripts-de-tu-c-243-digohtml.aspx
Si miras el cdigo fuente HTML que genera la llamada a Html.EditorFor(x=>ValorPar) vers lo siguiente:
<div class="editor-field">
<input class="text-box single-line" data-val="true" data-val-number="The field ValorPar must be
a number." data-val-numeropar="El nmero debe ser par." data-val-range="Positivo menor que 100"
data-val-range-max="100" data-val-range-min="1" data-val-required="The ValorPar field is required."
id="ValorPar" name="ValorPar" type="text" value="" />
<span class="field-validation-valid" data-valmsg-for="ValorPar" data-valmsgreplace="true"></span>
</div>

Todos los atributos data-val que contiene el <input> son para las validaciones usando javascript no obtrusivo. De hecho
puedes observar que existe un atributo llamado data-val-numeropar. Ese atributo se ha generado porque precisamente
hemos implementado IClientValidatable en nuestro atributo de servidor. Bien, por un lado tenemos un validador
llamado "numeropar" que hemos dado de alta en jQuery Validate. Por otro tenemos el atributo data-val-numeropar que
se ha generado al implementar IClientValidatable en nuestro atributo. Tan solo nos falta indicar a jQuery Validate que
debe usar el validador llamado "numeropar" en todos aquellos campos que tengan el atributo "data-val-numeropar".
Para ello debemos usar el siguiente cdigo javascript:
$.validator.unobtrusive.adapters.addBool("numeropar");

Manual del Framework ASP.NET MVC: manuales/framework-asp-net-mvc.html


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

40

Tu mejor ayuda para aprender a hacer webs


www.desarrolloweb.com
Con este cdigo se enlaza el validador numeropar de jQuery Validate, con el atributo data-val-numeropar.
De hecho en el ejemplo el mismo nombre (numeropar)

para todo, cosa que yo os recomiendo, pero realmente tenemos


dos conceptos:
1. El nombre del validador que damos de alta en jQuery Validate
2. El nombre de la regla de validacin, es decir el nombre del atributo data-val-xx (donde xx se sustituye por el
nombre de la regla de validacin).
No es obligatorio usar el mismo nombre. Con el siguiente cdigo, dais de alta un validador llamado "numeropar" y lo
vinculis a la regla de validacin "np":
$.validator.addMethod("numeropar", function (value, element, param) {
return value % 2 == 0;
});
$.validator.unobtrusive.adapters.addBool("np", "numeropar");

Fijaos en el segundo parmetro del mtodo addBool: indica que la regla "np" debe validarse usando el validador
"numeropar" (si no se pone el parmetro se asume que el nombre es el mismo).
Por supuesto ahora la regla se llama "np", y no "numeropar", por lo que cuando se implemente IClientValidatable debe
usarse "np":
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata,
ControllerContext context)
{
yield return new ModelClientValidationRule
{
ErrorMessage = this.ErrorMessage,
ValidationType = "np"
};

Bueno, el cdigo completo de la vista quedara:


@model MvcApplication2.Models.DemoModel
<h2>
ViewPage1</h2>
<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")"
type="text/javascript"></script>
<script type="text/javascript">
$.validator.addMethod("numeropar", function (value, element, param) {
return value % 2 == 0;
});
$.validator.unobtrusive.adapters.addBool("np", "numeropar");
</script>
@using (Html.BeginForm())
{
@Html.ValidationSummary(true)
<fieldset>
<legend>DemoModel</legend>
<div class="editor-label">
@Html.LabelFor(model => model.ValorPar)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.ValorPar)
@Html.ValidationMessageFor(model => model.ValorPar)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}

Ahora s! Hemos creado una validacin propia y que se valida no solo en servidor sino tambin en cliente!

Manual del Framework ASP.NET MVC: manuales/framework-asp-net-mvc.html


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

41

Tu mejor ayuda para aprender a hacer webs


www.desarrolloweb.com

En resumen
Hemos visto cmo funciona el sistema de validaciones basadas en atributos en ASP.NET MVC3. Tambin hemos visto
lo sencillo que es crear nuestras propias validaciones usando atributos propios y como aadir validacin en cliente en
javascript. Por supuesto os animo a que entendis como funciona jQuery Validate (hemos visto el tipo de validadores
ms sencillos que existen, los que slo validan un valor, pero los hay que pueden recibir parmetros para validar rangos,
o hacer comparaciones). No entraremos ms en detalle en jQuery Validate porque cae fuera del mbito de este manual.
Y sobre las validaciones? Pues no hemos terminado todava
hay un par de cosillas ms que creo interesantes y que
veremos en el siguiente artculo!
Artculo por Eduard

Toms

Validaciones cruzadas
En este artculo del manual de ASP.NET MVC vamos a hablar sobre las validaciones cruzadas y las
validaciones remotas, dos mecanismos adicionales a los ya vistos para casos ms especficos.
En los dos artculos anteriores del manual de ASP.NET MVC hemos visto como usar los atributos de Data Annotations
para realizar validaciones y como crearnos nuestras propias validaciones tanto en servidor como en cliente.
Pero hay un escenario en el que el uso de Data Annotations no termina de encajar del todo bien: las validaciones
cruzadas. Es decir cuando la validacin de un campo depende del valor de otro campo. As, un campo puede ser
obligatorio solo si en otro campo se ha entrado un valor especfico, o bien podemos tener dos campos mutuamente
excluyentes pero que uno de los dos deba ser informado s o s. Seguro que se te ocurren mil ejemplos!
Tcnicamente usando Data Annotations (en ASP.NET MVC 3) es posible crear este tipo de validaciones, p.ej. el
atributo Compare compara el valor de dos propiedades y falla si no son iguales (se usa para el caso tpico de entrar
password y comprobar password en formularios de registro). Pero para escenarios ms complejos que puedan
involucrar varias propiedades, en casos en que sea necesario tratar al viewmodel como un todo, ASP.NET MVC
proporciona un mecanismo muy sencillo y eficaz: la interfaz IValidatableObject.

IValidatableObject
Esta interfaz, que forma parte del .NET Framework 4, es usada por el runtime de ASP.NET MVC para realizar las
validaciones cruzadas. Tiene un solo mtodo llamado Validate que debe devolver una coleccin de resultados de
validacin. Su implementacin es trivial:
public class UsuarioViewModel : IValidatableObject
{
public string Nombre { get; set; }
public string Password { get; set; }
public string CompararPassword { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (string.IsNullOrEmpty(Nombre))
{
yield return new ValidationResult("No puede estar vaco.", new List<string> { "Nombre" });
}
if (Password != CompararPassword)
{
yield return new ValidationResult("Deben ser iguales.", new List<string> { "Password",
"CompararPassword" });
}
}
}

Listado : Implementacin de IValidatableObject


La clave de este mtodo es que slo devuelve errores. No devuelve true o false para indicar si todo ha ido bien o no.

Manual del Framework ASP.NET MVC: manuales/framework-asp-net-mvc.html


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

42

Tu mejor ayuda para aprender a hacer webs


www.desarrolloweb.com
Simplemente devuelve una coleccin de todos los errores encontrados. Cada ValidationResult devuelto contiene el
mensaje de error y (opcionalmente) una lista con los nombres de las propiedades que se han visto involucradas en este
error (a nivel tcnico de ASP.NET MVC podemos decir que el valor que devolvamos aqu se aade a la coleccin Error
de todas aquellas entradas del ModelState cuya clave est contenida en esta lista de nombres de propiedades).
Dada esta implementacin de IValidatableObject si el usuario deja el nombre vaco y entra dos passwords que no
coinciden, el ModelState que recibe el controlador es:

Fjate como el primer error devuelto (que el nombre no puede estar vaco) est asociado a la coleccin Errors del
elemento 0 del ModelState (cuya clave es Nombre). Por otro lado el error de que las passwords deben ser iguales est
asociado tanto al elemento 1 (Password) y 2 (CompararPassword) del ModelState, porque en el mtodo Validate lo
hemos devuelto asociado a esas dos propiedades. Si se usan los helpers para crear formularios (que ya hemos visto en
este manual) la pantalla mostrar todos los errores.

En resumen, IValidatableObject proporciona un mecanismo rpido y sencillo para realizar validaciones cruzadas en
nuestros viewmodels.
Una ltima observacin a tener presente es que ASP.NET MVC tan solo invoca el mtodo Validate si las validaciones
por atributos han pasado. Es decir, si hay un solo atributo de Data Annotations que falla, el mtodo Validate() no es
invocado.

Validaciones remotas
El ltimo tipo de validacin que nos queda por ver, es la validacin remota. Esta validacin es validacin en cliente (por
lo que como digo siempre es un tema de usabilidad y no de seguridad) y consiste en llamar usando Ajax a una funcin
de un controlador que nos indique si los valores actuales son correctos o no. Es pues una manera efectiva y rpida de
realizar en cliente validaciones que requieren acceder a recursos del servidor. P.ej. se podra validar que un nombre de
un usuario no est dado de alta. Esta validacin se realizara en cliente pero implica ejecutar un mtodo del servidor (ya
que es donde se pueden consultar todos los usuarios de la aplicacin). El mecanismo de validaciones remotas de
ASP.NET MVC pone muy fcil el realizar estas validaciones al encargarse automticamente de realizar todas las
llamadas Ajax.

Habilitando la validacin remota


Para habilitar la validacin remota sobre una propiedad de nuestro viewmodel se usa un atributo de DataAnnotations,
concretamente el atributo Remote. Su uso es extremadamente sencillo:
[Remote("ValidarNombre", "Usuarios", ErrorMessage = "Nombre invlido!")]
public string Nombre { get; set; }

Listado : Uso del atributo [Remote] en una propiedad


Basta con indicarle el nombre de la accin que deber usarse para validar (ValidarNombre), el controlador y el mensaje
de error a mostrar. Opcionalmente se puede aadir un parmetro HttpMethod que es el verbo http a usar para la llamada
Ajax (se asume GET si no se pone nada).
Ahora tan solo nos queda declarar la accin ValidarNombre. Dicha accin recibir como parmetro el valor de la
propiedad que se valida (Nombre en nuestro caso) y debe devolver un booleano que indique si la validacin ha ido bien
(true) o no (false). El nico detalle es que en lugar de devolver HTML, debe devolver un objeto JSON que contenga el
valor booleano. Aunque no hemos visto (todava) como devolver algo que no sea HTML en ASP.NET MVC, devolver
JSON es trivial: basta con usar el mtodo Json y pasarle un objeto .NET que ser serializado al cliente en formato
JSON. As el cdigo queda como:
[OutputCache(Location = OutputCacheLocation.None, NoStore = true)]

Manual del Framework ASP.NET MVC: manuales/framework-asp-net-mvc.html


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

43

Tu mejor ayuda para aprender a hacer webs


www.desarrolloweb.com
public ActionResult ValidarNombre(string nombre)
{
return Json(!string.IsNullOrEmpty(nombre) && "admin" != nombre && "sa" != nombre,
JsonRequestBehavior.AllowGet);
}

Listado : Accin usada para validacin remota


Si te preguntas para que sirve el atributo [OutputCache] con el que estamos decorando la accin es para que ASP.NET
MVC enve los headers correspondientes para que esta respuesta no pueda ser cacheada. Ya hablaremos en otro artculo
sobre temas de caching en ASP.NET MVC. De momento solo comentar que es necesario que lo incluyas en todas tus
acciones que uses para validaciones remotas, ya que si no su respuesta podra ser cacheada!
Y listos, no es necesario hacer nada ms. Ahora a medida que el usuario va entrando el nombre este se valida usando la
validacin remota. S, s, eso es una peticin http cada vez que el usuario pulsa una tecla en el campo de texto
Nombre Ten eso en cuenta cuando apliques validaciones remotas.
No profundizaremos ms en el tema de validaciones remotas, si quieres hacerlo puedes leer un post de mi blog que puse
hace algn tiempo al respecto: http://geeks.ms/blogs/etomas/archive/2011/01/14/asp-net-mvc3-validaci-243-nremota.aspx
Y recuerda (a riesgo de hacerme pesado) que eso son validaciones en cliente. No son para garantizar la seguridad de tu
aplicacin. Son para mejorar la experiencia de usuario.
Artculo por Eduard

Toms

Vdeo: Webcast ASP.NET MVC


Grabacin del webcast sobre ASP.NET MVC realizado el da 14 de marzo de 2012 a cargo de Eduard Toms,
organizado por DesarrolloWeb.com y Microsoft Eventos.
Quizs los lectores de este artculo conozcan ya a Eduard Toms, el ilustre colaborador que est creando para
DesarrolloWeb.com el Manual sobre el framework ASP.NET MVC. Pues bien, se conozca o no a este experto gestor de
proyectos en .NET, os informamos que el otro da estuvo con todos nosotros para ofrecernos dos horas de formacin
intensiva sobre tecnologas Microsoft y cmo ASP.NET MVC nos puede ayudar en nuestro da a da como
desarrolladores de sitios web.
El evento fue realizado en colaboracin con Microsoft, que nos cedi la plataforma Live Meeting para retransmitirlo a
todo el mundo. Nos sentimos orgullosos de afirmar que fue todo un xito! Seguro que, adems de nosotros mismos, los
asistentes se quedaron impactados de todas las cosas que pudimos aprender en poco tiempo sobre la plataforma .NET,
pero a decir verdad fueron comunicados muchos conocimientos en poco tiempo. Por ello, tanto las personas que
asistieron al evento como las personas que no pudieron estar presentes, nos han pedido publicar el vdeo de la charla de
Eduard, para verlo con ms calma desde sus ordenadores y en cualquier momento.
Dicho y hecho, en este artculo os presentamos justamente el webcast de Eduard, con toda su extensin, incluida la
intensa serie de preguntas con las que los asistentes literalmente alquilaron a nuestro ilustre ponente y que, a decir
verdad, muy gentilmente respondi.
Antes de dejaros con el vdeo, quiero sealar varios asuntos que pueden ser importantes para conocer por vuestra parte:
Grabacin del evento:
El evento se grab de dos maneras. La primera y ms lgica, fue la que la propia plataforma Live Meeting ofrece. Esa
grabacin la disponibilizar Microsoft en su propio sitio de Eventos Web, pero todava no es encuentra online en el
momento de escribir estas lneas.
La segunda opcin fue realizada por Alvaro Martnez @amargua, del equipo de DesarrolloWeb.com, que asisti a la
conferencia y grab el escritorio con la entrada de audio. Esa es la grabacin que ahora mismo estamos disponibilizando
para todos los lectores de DesarrolloWeb.com.

Manual del Framework ASP.NET MVC: manuales/framework-asp-net-mvc.html


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

44

Tu mejor ayuda para aprender a hacer webs


www.desarrolloweb.com
Tener en cuenta que, al ser la grabacin de escritorio de un asistente, pueden producirse pequeos fallos en el audio y la
imagen, que esperamos sean lo menores posibles. Nosotros hemos apreciado que la produccin final tiene la suficiente
calidad como para ser asistida sin mayores problemas.
Ejemplos realizados con el framework ASP.NET MVC:
El ponente, Eduard, nos ha comentado que en breve har disponibles a los asisntentes a la conferencia y a los que se
suscribieron a travs de DesarrolloWeb.com, los cdigos realizados en el webcast. Esperamos enlazarlos de aqu mismo
en un par de das ms.
Quieres aprender ms ASP.NET MVC?
Como se coment a lo largo de la charla, si quieres aprender mucho ms sobre este interesante framework y de la mano
de Eduard hacerte todo un experto en ASP.NET MVC, tenemos un curso que sin duda te va a interesar.
Se trata de una oportunidad excelente para aprender todo lo que has visto en el Webcast y mucho mucho ms, de una
manera detallada, pausada y con innmeros ejemplos y prcticas. Todos los que estn deseando aprender las mejores
tecnologas Microsoft para el desarrollo de aplicaciones web encontrarn en este curso todo lo que necesitan para hacer
realidad sus objetivos.
Para obtener ms informacin de este curso organizado por DesarrolloWeb.com y que tiene como tutor al propio Eduard
Toms, os recomendamos acceder a la pgina del curso: http://www.desarrolloweb.com/curso-aspnet-mvc/

Vdeo del webcast ASP,NET MVC


A continuacin os dejamos con el webcast, que esperamos satisfaga vuestra curiosidad sobre este interesante framework
para desarrollo de aplicaciones web.
Artculo por Miguel

Angel Alvarez

Manual del Framework ASP.NET MVC: manuales/framework-asp-net-mvc.html


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

45

Vous aimerez peut-être aussi