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:
- El nombre para la ruta: que nos permite identificarla y distinguirla de las demás rutas que definamos (podemos crear tantas como necesitemos).
- 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.
- 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:
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:
¡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:
(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:
Este es el aspecto de la aplicación en ejecución:
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!