Manual Framework Asp Net PDF
Manual Framework Asp Net PDF
www.desarrolloweb.com
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.
Toms
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
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.
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();
}
}
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>
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):
Toms
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 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).
class Usuario
string Nombre { get; set; }
string Twitter { get; set; }
DateTime Alta { get; set; }
10
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).
Toms
11
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>
12
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 />
13
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.
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>
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>
}
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
14
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
15
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}.
16
vale Home
por defecto.
El valor de ruta action
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
17
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:
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
18
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
y action)
19
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).
20
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
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:
21
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.
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
22
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).
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):
23
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
24
Esta vista crea un formulario que ser enviado por POST. El formulario contiene:
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
25
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"/>
26
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
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 />
27
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 :)
28
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:
Tenemos que realizar manualmente las dos tareas que el helper hace por nosotros:
29
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).
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:
30
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)
31
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
32
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.
33
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:
34
</p>
</fieldset>
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!
35
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).
36
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.
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
37
Toms
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
38
Y podramos comprobar como en efecto tan solo podemos entrar nmeros pares, comprendidos entre 1 y 100:
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.
39
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.
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");
40
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"
};
Ahora s! Hemos creado una validacin propia y que se valida no solo en servidor sino tambin en cliente!
41
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" });
}
}
}
42
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.
43
Toms
44
Angel Alvarez
45