[ASP.NET MVC] Pasar parámetros a través del PathInfo

¡Muy buenas! Bueno, el título del post no queda demasiado claro, pero a ver si consigo explicar un poco la idea. 😉

Los que habéis usado ASP.NET MVC estáis muy acostumbradas a las URLs del estilo /controlador/accion/id, es decir algo como:

  • /Home/Index/10
  • /Articles/View/Eiximenis
  • /Blog/View/10293

Sabemos que gracias a la tabla de rutas podemos pasar tantos parámetros como queramos, y así podríamos tener URLs del tipo:

  • /Articles/View/Eiximenis/MVC/2011

Que podría devolverme los articulos de “Eiximenis” con el tag “MVC” y del año 2011.

El único punto a tener presente es que el orden de los parámetros importa, es decir no es lo mismo /Articles/View/Eiximenis/MVC/2011 que /Articles/View/2011/MVC/Eiximenis. En el primer caso buscamos los artículos de Eiximenis sobre MVC en el 2011 y en el segundo caso buscaríamos los artículos del blogger 2011, sobre MVC en el año de Eiximenis. Y sin duda Fra Francesc Eiximenis, fue un gran escritor, pero que yo sepa todavía no se le ha dedicado un año (algo totalmente injusto, por supuesto :p).

En este artículo quiero enseñaros una manera para que podáis gestionar URLs del tipo:

  • /Articles/View/Author/Eiximenis/Tag/MVC/Year/2011
  • /Articles/View/Tag/MVC/Year/2011/Author/Eiximenis

Y que ambas URLs sean tratadas de forma idéntica. En este caso estaríamos pasando tres parámetros: Author, Tag y Year.

Para conseguir este efecto nos bastan dos acciones muy simples: definir un route handler nuevo y una entrada a la tabla de rutas.

El route handler lo único que debe hacer es recoger la información de la URL y parsearla en “tokens” (usando el ‘/’ como separador). Y por cada par de tokens añadir una entrada en los valores de ruta (route values). El código es muy simple:

public class UrlRouteHandler : MvcRouteHandler
{
protected override IHttpHandler GetHttpHandler(RequestContext requestContext)
{
var path = requestContext.RouteData.Values["pathInfo"];
if (path != null)
{
var tokens = path.ToString().Split('/');
for (var idx =0; idx<tokens.Length; idx+=2)
{
if (idx+1 < tokens.Length)
{
requestContext.RouteData.Values.Add(tokens[idx], tokens[idx+1]);
}
}
}

return base.GetHttpHandler(requestContext);
}
}

Una pequeña nota es que la cadena que separamos en tokens, no es toda la URL sino “pathInfo” un parámetro de ruta que ya nos vendrá dado. Este parámetro de ruta contendrá todo aquello que no es ni el controlador ni la acción. Es decir en la URL /Articles/View/Author/Eiximenis/Tag/MVC/Year/2011 el valor de pathInfo será Author/Eiximenis/Tag/MVC/Year/2011 (que son justo los parámetros).

Ahora nos queda añadir la entrada a la tabla de rutas. En mi ejemplo yo he eliminado la entrada “Default” que genera VS2010 y la he sustituído por:

routes.Add("Default", new Route(url: "{controller}/{action}/{*pathInfo}",
routeHandler: new UrlRouteHandler(),
defaults: new RouteValueDictionary(new {controller = "Home", action = "Index"})));

La clave aquí está en el {*pathInfo}. Aquí le digo al sistema de rutas que coja todo lo que venga después de /{controller}/{action} y me lo añada a un parámetro de ruta llamado pathInfo. Además de eso, en esta ruta le indico que su routeHandler será una instancia de la clase UrlRouteHandler que hemos creado antes.

Y listos! Una vez los datos están en el route value ya puede entrar en acción el sistema de binding de ASP.NET MVC lo que quiere decir que puedo crear un controlador como el siguiente:

public class ArticlesController : Controller
{
public ActionResult View(string author, string tag, int? year)
{
dynamic data = new ExpandoObject();
data.Author = author ?? "Sin formato";
data.Tag = tag ?? "Sin confirmación";
data.Year = year.HasValue ? year.ToString() : "Sin año";
return View(data);
}
}

Que recibiría los parámetros de las URLs que hemos visto anteriormente.

Un saludo a todos!

4 comentarios sobre “[ASP.NET MVC] Pasar parámetros a través del PathInfo”

  1. Buenas Noches, Estoy aprendiendo mvc y me ha parecido este blog excelente.
    Tengo una pregunta necesito una ruta de este tipo
    Usuario/CambiarPago/1/2

    estaba intentando esto
    routes.MapRoute(
    «Default», // Route name
    «{controller}/{action}/{id}/{id2}», // URL with parameters
    new { controller = «Partido», action = «Index», id = UrlParameter.Optional,id2 = UrlParameter.Optional } // Parameter defaults
    );
    pero no funciona

    Me podria indicar como hacerlo
    gracias

  2. @camilo
    La definición de la ruta la veo bien. Ten presente pero nunca generar una URL con id2 y sin id (generará una URL no válida).

    Y luego para generar una URL de este tipo debes:
    @Html.ActionLink(«texto», «Usuario»,»CambiarPago», new { id=1, id2=2})

    Esto te debería funcionar… ya me dirás! 🙂

    Saludos!

  3. Gracias , por la respuesta, lo que quiero hacer es que
    pueda recibir rutas sin parametros(id,id2) o rutas con id pero sin id2, o rutas con id y id2.

  4. @Camilo
    Te tendría que funcionar.

    /Partido/Index -> Invoca acción sin id ni id2
    /Partido/Index/1 -> Invoca con id =1 y sin id2
    /Partido/Index/1/2 -> Invoca con id=1 y id2=2

    Recuerda que en el controlador los parámetros DEBEN ser nullables! O bien usas int? si son enteros o string (o cualquier otra clase).

    Ya dirás… 😉

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *