En toda aplicación web hay dos mecanismos básicos que se usan para pasar información de cliente al servidor: usando la URL (lo que se conoce como querystring) o usando un formulario (lo que se conoce como POST).
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 acción Index de HomeController con dos parámetros p1 (con valor 10) y p2 con valor no. Así en el controlador podríamos tener definida la acción de la siguiente forma:
public ActionResult Index(int p1, string p2)
{
// Codigo...
}
Los nombres de los parámetros deben coincidir con los nombres de los parámetros de la querystring. Bien, fijaos que dado que hemos declarado el parámetro p1 como int sólo podemos pasar valores enteros, mientras que en el parámetro p2, podemos pasar cualquier cadena. Si pasamos una cadena en el parámetro p1, p.ej. la url http://host/home/index?p1=texto&p2=otrotexto el error que recibimos es el siguiente:
Lo que ha ocurrido es que ASP.NET MVC ha intentado convertir el valor de p1 (texto) a un entero. Al no poder hacerlo, internamente asigna null al valor del parámetro p1, pero luego cuando debe invocar el método Index y pasarle un int se encuentra que int no acepta valores null. De aquí el error que recibimos.
Como podríamos evitar esto? Bueno
una manera fácil y sencilla es usar int? (es decir Nullable
public ActionResult Index(int? p1, string p2)
Ahora si invocamos la url y el valor de p1 no es numérico, nos llegará null, mientras que si el valor de p1 es numérico recibiremos su valor.
La regla es realmente muy simple: Si quieres que un parámetro de querystring sea opcional debes usar un tipo por referencia (es decir una clase como string o Nullable
Pulsa <a href="/Home/View?pid=10">aquí</a> para ver los detalles
Este código tiene dos errores fundamentales.
Pulsa <a href="@Url.Action("View","Home")?pid=10">aquí</a> para ver los detalles
Si ejecutamos eso y miramos el código HTML veremos que es exactamente lo que habíamos tecleado antes (debido a que usamos la tabla de rutas estándar). Pero si añado una entrada a la tabla de rutas, dejándola así:
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
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 necesitéis 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 estarán en la forma /controlador/acción es una muy mala práctica (y como decía antes, un error común al principio).
Los parámetros 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 parámetro de ruta. ¿De cuál? Pues el nombre debe estar explicitado en la tabla de rutas. Vamos a suponer que usamos la tabla de rutas estándar. En este caso el nombre de dicho parámetro es id. Ahora yo os pregunto
que ocurriría si usamos la URL http://host/controlador/accion/10?id=20 ?
Fijaos que la cuestión no es baladí: a nuestro controlador le estamos pasando:
Pues lo que recibiremos en nuestra acción será el valor del parámetro de ruta (es decir 10, en lugar de 20):
Eso es debido a que comentábamos antes: ASP.NET MVC mezcla todos los parámetros que le llegan antes de enlazarlos con los controladores y lo hace según una cierta prioridad. Y los parámetros de ruta (cuyo nombre se define en la tabla de rutas) tienen más prioridad. Eso debería tenerlo en cuenta cuando genero URLs, es decir, en este caso debería generar URLs usando la convención /controlador/acción/valor_id antes que /controlador/acción?id=valor_id
Al final eso nos implica que no deberíamos nunca generar las URLs con parámetros querystring añadidos 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 anónimo cuyas propiedades son los valores a mandar al controlador. ¡Url.Action es lo suficientemente inteligente como para usar valores de ruta si están definidos y querystring en caso de que no!
Así pues si tenemos la tabla de rutas estándar y tenemos las siguientes llamadas a Url.Action:
Url 1: @Url.Action("Index", "Home", new { id = 20 })
La respuesta generada por esa vista es la siguiente:
Url 1: /Home/Index/20
¿No es una maravilla? Url.Action sabe que id es un parámetro 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 acción en el controlador la tenemos definida:
public ActionResult Index(string id, string otro_id)
Fijaos como desde el controlador recibimos de igual manera parámetros de ruta que parámetros que vengan por querystring
:)
En el siguiente artículo del tutorial vamos a ver como mandar datos de formularios a las vistas, es decir cómo usar POST.
{
// Codigo
}
Generar URLs con querystrings desde las vistas
Uno de los errores más frecuentes en ASP.NET MVC es tener código en las vistas que sea parecido a este:
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 método Url.Action. Su firma básica es Url.Action (acción, controlador). Así el código anterior lo podemos reescribir de la forma:
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
);
Parámetros querystring y route values
Vamos a ver ahora que significa el segundo de los errores que cometíamos (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 parámetros que le llegan antes de pasarlos a los controladores. A un controlador le pueden llegar parámetros por tres formas básicas (vale, eso no es del todo cierto, hay más formas pero vamos a ignorarlas de momento): como parámetros de ruta, como querystring y como POST (de esos hablaremos en un artículo posterior).
Ambos parámetros (de ruta y querystring) se mapean a parámetros de la acción del controlador. ¿Así pues
que valor recibiremos en el parámetro id de nuestra acción? ¿O bien ASP.NET MVC generará un error?
Url 2: @Url.Action("Index", "Home", new { id = 20, otro_id=30})
Url 3: @Url.Action("Index", "Home", new {otro_id=30})
Url 2: /Home/Index/20?otro_id=30
Url 3: /?otro_id=30
{
return View();
}
Eduard Tomàs
Apasionado de la informática, los videojuegos, rol y... la cerveza. Key Consulta...