Compartir a través de


Enrutamiento de direcciones URL

por Erik Reitan

Descarga del proyecto de ejemplo (C#) Wingtip Toys o Descarga del libro electrónico (PDF)

En esta serie de tutoriales se enseñan los conceptos básicos de la compilación de una aplicación ASP.NET Web Forms mediante ASP.NET 4.5 y Microsoft Visual Studio Express 2013 para Web. Como acompañamiento a esta serie de tutoriales, hay disponible un proyecto con código fuente de C# de Visual Studio 2013.

En este tutorial, modificará la aplicación de ejemplo Wingtip Toys para admitir el enrutamiento de direcciones URL. El enrutamiento permite que la aplicación web use direcciones URL que sean fáciles de recordar y que sean mejor compatibles con los motores de búsqueda. Este tutorial se basa en el tutorial anterior "Pertenencia y administración" y forma parte de la serie de tutoriales Wingtip Toys.

Temas que se abordarán:

  • Cómo registrar rutas para una aplicación ASP.NET Web Forms.
  • Cómo agregar rutas a una página web.
  • Cómo seleccionar datos de una base de datos para admitir rutas.

Introducción al enrutamiento de ASP.NET

El enrutamiento de direcciones URL permite configurar una aplicación para aceptar direcciones URL de solicitud que no se asignan a archivos físicos. Una dirección URL de solicitud es simplemente la dirección URL que un usuario escribe en su explorador para buscar una página en el sitio web. El enrutamiento se usa para definir direcciones URL que son semánticamente significativas para los usuarios y que pueden ayudar con la optimización del motor de búsqueda (SEO).

De forma predeterminada, la plantilla de Web Forms incluye URL descriptivas de ASP.NET. Gran parte del trabajo de enrutamiento básico se implementará mediante direcciones URL descriptivas. Sin embargo, en este tutorial agregará funcionalidades de enrutamiento personalizadas.

Antes de personalizar el enrutamiento de direcciones URL, la aplicación de ejemplo Wingtip Toys puede vincularse a un producto mediante la siguiente dirección URL:

https://localhost:44300/ProductDetails.aspx?productID=2

Al personalizar el enrutamiento de direcciones URL, la aplicación de ejemplo Wingtip Toys se vinculará al mismo producto mediante una dirección URL de lectura más fácil:

https://localhost:44300/Product/Convertible%20Car

Rutas

Una ruta es un patrón de dirección URL que se asigna a un controlador. El controlador puede ser un archivo físico, como un archivo .aspx en una aplicación Web Forms. Un controlador también puede ser una clase que procesa la solicitud. Para definir una ruta, cree una instancia de la clase Route especificando el patrón de dirección URL, el controlador y, opcionalmente, un nombre para la ruta.

Agregue la ruta a la aplicación agregando el objeto Route a la propiedad estática Routes de la clase RouteTable. La propiedad Routes es un objeto RouteCollection que almacena todas las rutas de la aplicación.

Patrones de dirección URL

Un patrón de dirección URL puede contener valores literales y marcadores de posición de variables (denominados parámetros de dirección URL). Los literales y los marcadores de posición se encuentran en segmentos de la dirección URL que están delimitados por el carácter de barra diagonal (/).

Cuando se realiza una solicitud a la aplicación web, la dirección URL se analiza en segmentos y marcadores de posición, y los valores de variable se proporcionan al controlador de solicitudes. Este proceso es similar a la forma en que se analizan los datos de una cadena de consulta y se pasan al controlador de solicitudes. En ambos casos, la información de variables se incluye en la dirección URL y se pasa al controlador en forma de pares clave-valor. En el caso de las cadenas de consulta, las claves y los valores se encuentran en la dirección URL. En el caso de las rutas, las claves son los nombres de marcador de posición definidos en el patrón de dirección URL y solo los valores están en la dirección URL.

En un patrón de dirección URL, se definen marcadores de posición mediante la inclusión de llaves ( { y } ). Puede definir más de un marcador de posición en un segmento, pero los marcadores de posición deben estar separados por un valor literal. Por ejemplo, {language}-{country}/{action} es un patrón de ruta válido. Sin embargo, {language}{country}/{action} no es un patrón válido, porque no hay ningún valor literal ni delimitador entre los marcadores de posición. Por lo tanto, el enrutamiento no puede determinar dónde separar el valor del marcador de posición de idioma del valor del marcador de posición del país.

Asignación y registro de rutas

Para poder incluir rutas a páginas de la aplicación de ejemplo Wingtip Toys, debe registrar las rutas cuando se inicie la aplicación. Para registrar las rutas, modificará el controlador de eventos Application_Start.

  1. En el Explorador de soluciones de Visual Studio, busque y abra el archivo Global.asax.cs.

  2. Agregue el código resaltado en amarillo al archivo Global.asax.cs de la siguiente manera:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Optimization;
    using System.Web.Routing;
    using System.Web.Security;
    using System.Web.SessionState;
    using System.Data.Entity;
    using WingtipToys.Models;
    using WingtipToys.Logic;
    
    namespace WingtipToys
    {
        public class Global : HttpApplication
        {
            void Application_Start(object sender, EventArgs e)
            {
              // Code that runs on application startup
              RouteConfig.RegisterRoutes(RouteTable.Routes);
              BundleConfig.RegisterBundles(BundleTable.Bundles);
    
              // Initialize the product database.
              Database.SetInitializer(new ProductDatabaseInitializer());
    
              // Create custom role and user.
              RoleActions roleActions = new RoleActions();
              roleActions.AddUserAndRole();
    
              // Add Routes.
              RegisterCustomRoutes(RouteTable.Routes);
            }
    
            void RegisterCustomRoutes(RouteCollection routes)
            {
              routes.MapPageRoute(
                  "ProductsByCategoryRoute",
                  "Category/{categoryName}",
                  "~/ProductList.aspx"
              );
              routes.MapPageRoute(
                  "ProductByNameRoute",
                  "Product/{productName}",
                  "~/ProductDetails.aspx"
              );
            }
        }
    }
    

Cuando se inicia la aplicación de ejemplo Wingtip Toys, llama al controlador de eventos Application_Start. Al final de este controlador de eventos, se llama al método RegisterCustomRoutes. El método RegisterCustomRoutes agrega cada ruta llamando al método MapPageRoute del objeto RouteCollection. Las rutas se definen mediante un nombre de ruta, una dirección URL de ruta y una dirección URL física.

El primer parámetro ("ProductsByCategoryRoute") es el nombre de la ruta. Se usa para llamar a la ruta cuando es necesario. El segundo parámetro ("Category/{categoryName}") define la dirección URL de reemplazo descriptivo que puede ser dinámica en función del código. Esta ruta se usa al rellenar un control de datos con vínculos generados en función de los datos. Se muestra una ruta como se indica a continuación:

routes.MapPageRoute(
      "ProductsByCategoryRoute",
      "Category/{categoryName}",
      "~/ProductList.aspx"
  );

El segundo parámetro de la ruta incluye un valor dinámico especificado por llaves ({ }). En este caso, el categoryName es una variable que se usará para determinar la ruta de enrutamiento adecuada.

Nota:

Opcional

Es posible que le resulte más fácil administrar el código moviendo el método RegisterCustomRoutes a una clase independiente. En la carpeta Logic, cree una clase RouteActions independiente. Mueva el método RegisterCustomRoutes anterior del archivo Global.asax.cs a la nueva clase RoutesActions. Use la clase RoleActions y el método createAdmin como ejemplo de cómo llamar al método RegisterCustomRoutes desde el archivo Global.asax.cs.

Es posible que también haya observado la llamada al método RegisterRoutes mediante el objeto RouteConfig al principio del controlador de eventos Application_Start. Esta llamada se realiza para implementar el enrutamiento predeterminado. Se incluyó como código predeterminado al crear la aplicación mediante la plantilla de Web Forms de Visual Studio.

Recuperación y uso de datos de ruta

Como se mencionó anteriormente, se pueden definir rutas. El código que agregó al controlador de eventos Application_Start en el archivo Global.asax.cs carga las rutas definibles.

Establecer rutas

Las rutas requieren que agregue código adicional. En este tutorial, usará el enlace de modelos para recuperar un objeto RouteValueDictionary que se usa al generar las rutas mediante datos de un control de datos. El objeto RouteValueDictionary contendrá una lista de nombres de producto que pertenecen a una categoría específica de productos. Se crea un vínculo para cada producto en función de los datos y la ruta.

Habilitar rutas para categorías y productos

A continuación, actualizará la aplicación para que use el ProductsByCategoryRoute para determinar la ruta correcta que se va a incluir para cada vínculo de categoría de producto. También actualizará la página ProductList.aspx para incluir un vínculo enrutado para cada producto. Los vínculos se mostrarán tal como estaban antes del cambio, pero los vínculos ahora usarán el enrutamiento de direcciones URL.

  1. En el Explorador de soluciones, abra la página Site.Master si aún no está abierta.

  2. Actualice el control ListView denominado "categoryList" con los cambios resaltados en amarillo, por lo que el marcado aparece de la siguiente manera:

    <asp:ListView ID="categoryList"  
        ItemType="WingtipToys.Models.Category" 
        runat="server"
        SelectMethod="GetCategories" >
        <ItemTemplate>
            <b style="font-size: large; font-style: normal">
            <a href="<%#: GetRouteUrl("ProductsByCategoryRoute", new {categoryName = Item.CategoryName}) %>">
                <%#: Item.CategoryName %>
            </a>
            </b>
        </ItemTemplate>
        <ItemSeparatorTemplate>  |  </ItemSeparatorTemplate>
    </asp:ListView>
    
  3. En Explorador de soluciones, abra la página ProductList.aspx.

  4. Actualice el elemento ItemTemplate de la página ProductList.aspx con las actualizaciones resaltadas en amarillo, por lo que el marcado aparece de la siguiente manera:

    <ItemTemplate>
      <td runat="server">
        <table>
          <tr>
            <td>
              <a href="<%#: GetRouteUrl("ProductByNameRoute", new {productName = Item.ProductName}) %>">
                <image src='/Catalog/Images/Thumbs/<%#:Item.ImagePath%>'
                  width="100" height="75" border="1" />
              </a>
            </td>
          </tr>
          <tr>
            <td>
              <a href="<%#: GetRouteUrl("ProductByNameRoute", new {productName = Item.ProductName}) %>">
                <%#:Item.ProductName%>
              </a>
              <br />
              <span>
                <b>Price: </b><%#:String.Format("{0:c}", Item.UnitPrice)%>
              </span>
              <br />
              <a href="/AddToCart.aspx?productID=<%#:Item.ProductID %>">
                <span class="ProductListItem">
                  <b>Add To Cart<b>
                </span>
              </a>
            </td>
          </tr>
          <tr>
            <td>&nbsp;</td>
          </tr>
        </table>
        </p>
      </td>
    </ItemTemplate>
    
  5. Abra el código subyacente de ProductList.aspx.cs y agregue el siguiente espacio de nombres como resaltado en amarillo:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using WingtipToys.Models;
    using System.Web.ModelBinding;
    using System.Web.Routing;
    
  6. Reemplace el método GetProducts del código subyacente (ProductList.aspx.cs) por el código siguiente:

    public IQueryable<Product> GetProducts(
        [QueryString("id")] int? categoryId,
        [RouteData] string categoryName)
    {
        var _db = new WingtipToys.Models.ProductContext();
        IQueryable<Product> query = _db.Products;
    
        if (categoryId.HasValue && categoryId > 0)
        {
            query = query.Where(p => p.CategoryID == categoryId);
        }
    
        if (!String.IsNullOrEmpty(categoryName))
        {
            query = query.Where(p =>
                String.Compare(p.Category.CategoryName,
                categoryName) == 0);
        }
        return query;
    }
    

Agregar código para detalles del producto

Ahora, actualice el código subyacente (ProductDetails.aspx.cs) de la página ProductDetails.aspx para usar los datos de ruta. Tenga en cuenta que el nuevo método GetProduct también acepta un valor de cadena de consulta para el caso en el que el usuario tiene un vínculo marcado que usa la dirección URL no enrutada más antigua y no enrutada.

  1. Reemplace el método GetProduct del código subyacente (ProductDetails.aspx.cs) por el código siguiente:

    public IQueryable<Product> GetProduct(
            [QueryString("ProductID")] int? productId,
            [RouteData] string productName)
    {
        var _db = new WingtipToys.Models.ProductContext();
        IQueryable<Product> query = _db.Products;
        if (productId.HasValue && productId > 0)
        {
            query = query.Where(p => p.ProductID == productId);
        }
        else if (!String.IsNullOrEmpty(productName))
        {
            query = query.Where(p =>
                  String.Compare(p.ProductName, productName) == 0);
        }
        else
        {
            query = null;
        }
        return query;
    }
    

Ejecutar la aplicación

Ahora puede ejecutar la aplicación para ver las rutas actualizadas.

  1. Presione F5 para ejecutar la aplicación de ejemplo Wingtip Toys.
    El explorador se abre y muestra la página Default.aspx.
  2. Haga clic en el vínculo de Productos en la parte superior de la página.
    Todos los productos se muestran en la página ProductList.aspx. Se muestra la siguiente dirección URL (con el número de puerto) para el explorador:
    https://localhost:44300/ProductList
  3. A continuación, haga clic en el vínculo de la categoría Coches cerca de la parte superior de la página.
    Solo los coches se muestran en la página de ProductList.aspx. Se muestra la siguiente dirección URL (con el número de puerto) para el explorador:
    https://localhost:44300/Category/Cars
  4. Haga clic en el vínculo que contiene el nombre del primer automóvil que aparece en la página ("Coche convertible") para mostrar los detalles del producto.
    Se muestra la siguiente dirección URL (con el número de puerto) para el explorador:
    https://localhost:44300/Product/Convertible%20Car
  5. A continuación, escriba la siguiente dirección URL no enrutada (con el número de puerto) en el explorador:
    https://localhost:44300/ProductDetails.aspx?productID=2
    El código todavía reconoce una dirección URL que incluye una cadena de consulta, para el caso en el que un usuario tiene un vínculo marcado.

Resumen

En este tutorial, ha agregado rutas para categorías y productos. Ha aprendido cómo se pueden integrar las rutas con controles de datos que usan el enlace de modelos. En el siguiente tutorial, implementará el control global de errores.

Recursos adicionales

URL descriptivas de ASP.NET
Implementación de una aplicación segura de ASP.NET Web Forms con pertenencia, OAuth y SQL Database en Azure App Service
Microsoft Azure: prueba gratuita