JASoft.org

El blog de José Manuel Alarcón Aguín. Programación web y mucho más...

MENÚ - JASoft: JM Alarcón

Cómo crear URLs amigables personalizadas con ASP.NET Web Forms

Una de las ventajas que aducen los defensores a ultranza de ASP.NET MVC es lo bonitas y apropiadas para SEO que quedan sus URLs. Y tienen razón.

La típica URL para una página que muestre los detalles de un producto hecha con ASP.NET Web Forms tendría un aspecto análogo a este:

http:///www.miservidor.com/VerProducto.aspx?IDProd=5

Sin embargo, la misma funcionalidad usando ASP.NET MVC sería más bien algo más simple, del estilo de:

http:///www.miservidor.com/Ver/Producto/5

Estas URL estilo REST son muy útiles tanto de cara a hacer el sitio más amigable a los usuarios, como para facilitar la vida a las arañas de los buscadores, favoreciendo el posicionamiento de las páginas si éstas son parte de una aplicación pública.

¿Cómo podemos conseguir lo mismo en ASP.NET Web Forms?

Conseguir lo mismo en nuestras páginas Web Forms "tradicionales" es muy sencillo desde que apareció ASP.NET 4.0. Lo único que tenemos que hacer es definir las rutas que queremos usar, exactamente de la misma manera que lo hacemos con ASP.NET MVC.

Para ello abriremos nuestro archivo Global.asax y crearemos un método con el que definir las diferentes rutas, por ejemplo uno como este:

void DefinirRutas()
{
	RouteTable.Routes.MapPageRoute("Productos", "Info/Productos/{IDProd}", "~/VerProducto.aspx");
}

Hay que incluir una referencia al espacio de nombres System.Web.Routing.

A este método lo llamaremos desde el evento Application_start:

void Application_Start(object sender, EventArgs e)
{
	DefinirRutas();
}

Podríamos definir la ruta directamente en Application_Start, pero de este modo queda más limpio el código y tenemos una ubicación específica para poder definir y modificar las rutas de manera separada de cualquier otra cosa que hagamos al comienzo de la aplicación.

¿Qué es lo que se hace en el método MapPageRoute que hemos utilizado?

En el ejemplo hemos empleado la sobrecarga más común de este método que toma tres parámetros:

  1. El nombre para la ruta: que nos permite identificarla y distinguirla de las demás rutas que definamos (podemos crear tantas como necesitemos).
  2. Plantilla de URL para la ruta: definimos el aspecto que tendrá nuestra URL amigable, marcando los parámetros variables con sus nombres entre llaves. Así, en el ejemplo, sólo tenemos un parámetro variable al que le hemos llamado "IDProd". Podemos definir con las llaves tantos parámetros como necesitemos, aunque lo habitual es que sean dos o tres como mucho.
  3. Ruta relativa del archivo físico al que se corresponde: generalmente las URLs que escribimos en el navegador se corresponden con rutas físicas en el disco duro del servidor. En este caso las URLs amigables no existen y debemos indicar al servidor de aplicaciones a qué archivos físicos se corresponden en realidad 8algo que el usuario nunca verás). En este tercer parámetro se le indica la ruta en el servidor del archivo físico real que va a atender las peticiones entre bambalinas. En nuestro ejemplo es una página llamada VerProducto.aspx. La "tilde" o "virgulilla" (~, se escribe con ALT+0126 o ALT Gr + 4) del principio sirve para indicar, como siempre en ASP.NET, la carpeta raíz de nuestra aplicación.

Fantástico. Ahora nuestra ruta ya queda definida y si escribimos una URL que siga el patrón marcado se redirigirá la petición a nuestra página .aspx común de Web Forms.

¿Cómo recibimos los parámetros de la ruta en la página ASPX?

Para mostrar el funcionamiento de la ruta vamos a crear la página VerProducto.aspx, a la cual le añadiremos una etiqueta para el título, un control SqlDataSource y un control DetailsView. Podríamos haber utilizado cualquier otro control tanto de origen de datos (por ejemplo, un EntityDataSource que utilice Entity Frameworkpara el acceso a datos y una rejilla).

Configuramos el control SqlDataSource para realizar con él una consulta personalizada que consultará las tablas de Productos, Proveedores y Categorías de la archiconocida base de datos Northwind. La consulta es la siguiente:

RutasWF_1

Pulsamos siguiente y, al detectarse el parámetro @IDProd que hemos incluido en la consulta, se nos da la opción de vincularlo con algún origen para el mismo: una cookie, un parámetro de QueryString, etc...

En ASP.NET 4.0 ahora tenemos un nuevo tipo de origen para los parámetros de los DataSources: los datos de las rutas o RouteData. Basta con que seleccionemos esta opción en la listta desplegable, le indiquemos el nombre del parámetro de la URl al que lo queremos asociar (en nuestro ejemplo será el único que hay "IDProd"), y también, como siempre, un valor por defecto:

RutasWF_2

¡Listo! Pulsamos siguiente, terminamos, y a partir de este momento la consulta estará parametrizada a partir del valor del parámetro definido en la ruta.

Enlazamos el DataSource con la rejilla, la ponemos bonita y listo para funcionar. El aspecto de la página será similar a este en Visual Studio:

RutasWF_1

(también he añadido un enlace abajo para regresar a la página anterior).

Si ahora ejecutamos y escribimos una ruta del estilo de las definidas (por ejemplo, http://localhost:xxxx/Info/Producto/5) veremos que se muestran los detalles de los productos cambiando el ID al final de la misma (en el ejemplo descargable he incluido varios ejemplos).

Cómo detectamos los parámetros desde código

Lo anterior está muy bien pues nos facilita el trabajo con los controles de origen de datos, pero ¿qué pasa si queremos realizar operaciones manuales y obtener mediante código los valores de los distintos parámetros.

Las páginas ahora incorporan una nueva propiedad llamada RouteData con información sobre la ruta a través de la cual se la ha invocado. Gracias a ella y a su colección Values es muy sencillo obtener el valor de cualquier parámetro. En el ejemplo lo que hago para mostrar su uso combinado con lo anterior es colocar el ID del producto que hay en la ruta dentro de la etiqueta grande de título de la página, con este código que ilustro el uso de RouteData:

RutasWF_4

Este es el aspecto de la aplicación en ejecución:

RutasWF_5

Como vemos nuestro código ha extraído el valor "5" de la ruta ficticia a la página y la ha mostrado en el encabezado. El control DataSource la ha utilizado también para mostrar los detalles del producto.

Generar rutas para enlaces

Por supuesto, dado que nosotros mismos hemos definido las rutas, nos sabemos de memoria cómo generarlas, por lo que si queremos podemos colocar por toda la aplicación enlaces a productos usando la nueva ruta amigable no hay problema.

El problema vendrá si, por el motivo que sea, en el futuro necesitamos cambiar la sintaxis de la ruta y que sea de otra forma diferente. De repente todos los enlaces desperdigados por la aplicación dejarán de funcionar ¿vaya lio!

Para evitarlo la infraestructura de rutas de ASP.NET nos ofrece métodos para generar dinámicamente sobre la marcha esas rutas.

En concreto todos los controles ASP.NET Web Forms ahora disponen de un método GetRouteUrl que nos permite hacer precisamente eso. Las páginas ASPX heredan también de la clase Control, por lo que disponen de esta capacidad, y es posible utilizarlo también en expresiones de "binding" de datos. Por ejemplo, podemos colocar un enlace al producto con ID=5 usando este código:

lnkProd1.NavigateUrl = GetRouteUrl("Productos", new { IDProd = 1 });
lnkProd1.Text = lnkProd1.NavigateUrl;

El método toma como parámetros el identificador de la ruta y una clase cualquiera cuyas propiedades coincidan con los parámetros que hay que usar para generar la ruta. Dado que la clase puede ser cualquiera lo que se suele hacer es utilizar una clase anónima definida al vuelo, que es lo que he hecho en el código anterior.

Consideraciones adicionales

Las rutas son un mecanismo potente que nos puede ayudar a hacer las aplicaciones más amigables y más apropiadas para SEO.

Asegúrate de comprender las posibilidades de definición que nos ofrecen, y ten siempre en cuenta la precedencia de las rutas, es decir, que el orden en el que las defines es muy importante para que no se produzcan efectos no deseados. Si no planificamos adecuadamente la sintaxis y el orden de las rutas, una misma URL puede encajar en más de una definición y llevarnos a otra ubicación interna con la que no contábamos.

Puedes descargarte el sencillo ejemplo que he desarrollado para este post desde aquí (33,2 KB).

¡Espero que te sea útil!

Banner

Comentarios (17) -

Muy bueno! y muy simple, lastima que no se puede hacer con el net framework 3.5.
vendría a ser como el mod_rewrite de apache.

Responder

Estaba precisamente implementando ese código en un desarrolo y me está fallando por culpa de los directorios virtuales de IIS ¿se te ocurre qué puede estar pasando?
Un saludo.

Responder

Hola:

¿Qué te pasa exactamente? ¿No te encuentra las rutas?
Ten en cuenta que éstan referidas a la raíz de la aplicación, es decir, en tu caso sería a la carpeta virtual...

De todos modos he de decir que nunca las he usado en carpetas virtuales, sólo en servidores virtuales :-S

Saludos

JM

Responder

Buenas, ante todo buen artículo. Lo he seguido al pie de la letra pero ahora me encuentro con un problema que no se a que es debido. Cuando intento generar rutas para enlaces, sólo me funciona para controles como tienes puesto en el ejemplo, controles "HyperLink" con el campo "NavigateUrl". He intentado crear otros enlaces con otros controles "LinkButton" o "ImageButton" (con el campo "PostBackUrl") y en ninguno me funciona el enlace. Alguien me podría echar un cable??
Gracias de antemano!

Responder

Excelente entrada!!, tan solo 1 consulta, existe algúna técnica para lograr el mismo resultado Fwk 2.0 ó 3.5??

Tal vez algúna (*.dll) de terceros??

Salu2,

Johnny B.

Responder

Hola:

De hecho en 3.5 SP1 si usas IIS 7.x no tendrías problemas para hacer uso de estas características

Salu2

Responder

Nelson Gomez
Spain Nelson Gomez

Buenos dias amigo, excelente post. de verdad que te felicito. Me baje el demo que tienes y funciona a la perfeccion.

Te cuento que lo hago desde cero y lamentablemente no me funciona.

1.- Creo un proyecto web para f4.0
2.- Voy al Global.asax y coloco:

void DefinirRutas()
{
    RouteTable.Routes.MapPageRoute("Clientes", "{IDcliente}", "~/perfilcliente.aspx");
}

void Application_Start(object sender, EventArgs e)
{
    DefinirRutas();
}

3.- Luego me voy a la pagina perfil cliente: y coloco todo lo relacionado para que el parámetro colocado via url me lo asigne a la variable y como demostración coloco Response.Write(nombrevariable)

4.- Levanto default.aspx y coloco en la direccion http:localhostXXXX/4 y me dice que no encuentra la pagina.

Que estoy haciendo mal?
Que falta para que me pueda funcionar?

Espero tu valiosa respuesta...

Responder

José Manuel Alarcón
Spain José Manuel Alarcón

Hola:

¿Lo estás usando en IIS 7 o en el servidor de desarrollo? Si es IIS 7 asegúrate de que tienes el modo Integrado en el grupo de aplicaciones (no el modo clásico).

Saludos,

Responder

Nelson Gomez
Spain Nelson Gomez

Hola Jose manuel, gracias por responder lo mas pronto posible,

Bueno lo estoy haciendo en el servidor de desarrollo, ejecutándolo desde ahí, aun no lo coloco en el servidor de producción y nada que me funciona.

Responder

Nelson Gomez
Spain Nelson Gomez

Puedes por favor ayudarme a solucionar mi caso? de verdad Jose que me urge poder hacer algo así para mi app web.

A la espera de tu valiosa respuesta...

Responder

José M. Alarcón
Spain José M. Alarcón

¿Has seleccionado la versión 4.0 de .NET? Porque en versiones anteriores no funcionaría.

Si no es que no hay mucho más que hacer Siguiendo lo que indico en el post funciona perfectamente.

Saludos,

Responder

Nelson Gomez
Spain Nelson Gomez

Si amigo, esta seleccionado la 4.0

Responder

Nelson Gomez
Spain Nelson Gomez

Bueno yo voy tambien haciendo las cosas a mi modo.
te presento lo que tengo en el global

    void DefinirRutas()
    {
        System.Web.Routing.RouteTable.Routes.MapPageRoute("Clientes", "{cliente}", "~/perfilcliente.aspx");
    }
    
    void Application_Start(object sender, EventArgs e)
    {
        // Código que se ejecuta al iniciarse la aplicación
        DefinirRutas();
    }
    

y en perfilcliente.aspx.cs tengo:

    protected void Page_Load(object sender, EventArgs e)
    {
        string cliente = RouteData.Values["cliente"].ToString();
        Label1.Text = "Se ha solicitado información del cliente: " + cliente;
    }


en el web.config esta esto:

<?xml version="1.0"?>
<configuration>
  <system.web>
    <compilation debug="true" targetFramework="4.0"/>
  </system.web>
</configuration>

Amigo de verdad no se que estoy haciendo mal....
Puedes por favor ayudarme???

Responder

curioso que este blog no lo tenga implementado :P

Responder

Jos&#233; Manuel Alarc&#243;n
Spain José Manuel Alarcón

No es tan curioso: cuando este blog empezó a funcionar esto no existía. Por lo tanto si ahora cambio esto (es un simple ajuste en BlogEngine) de repente los cientos (o miles) de enlaces que hay por Internet apuntando aquí dejarían de funcionar, por lo que perdería mucho peso en búsquedas y demás. Dado que no quiero tampoco duplicar las URLs, se queda como está :-P

Responder

Entre la herramienta de webmaster tool de google y screaming frog, puedes analizar todas las url de tu blog, y así hacer redireccionamiento 301 a la nueva url amigable y así no perderías las relevancias de cada url.

Saludos

Responder

Jos&#233; Manuel Alarc&#243;n
Spain José Manuel Alarcón

Lo sé, pero no me apetece hacerlo por una cosa tan nimia... De hecho no me haría falta ni hacer eso: puedo escribir un código muy sencillo que intercepte las peticiones y haga esa redirección automáticamente, pero como digo no tengo ganas de hacerlo para el blog.

Gracias por el comentario.

Saludos.

Responder

Pingbacks and trackbacks (1)+

Agregar comentario

  Country flag

biuquote
  • Comentario
  • Vista previa
Loading