Enrutamiento de ASP.NET

Actualización: noviembre 2007

El enrutamiento ASP.NET permite usar direcciones URL que no es necesario asignar a archivos específicos de un sitio web. Dado que la dirección URL no tiene que asignarse a un archivo, en una aplicación web puede usar direcciones URL descriptivas de la acción del usuario, y por tanto, que los usuarios puedan identificar mejor.

En una aplicación ASP.NET que no utiliza enrutamiento, una solicitud entrante de una dirección URL normalmente se asigna a un archivo físico en el disco como un archivo .aspx. Por ejemplo, una solicitud de https://server/application/Products.aspx?id=4 se asigna a un archivo denominado Products.aspx que contiene código y marcado para representar una respuesta al explorador. La página web utiliza el valor de cadena de consulta de id=4 para determinar qué tipo de contenido debe mostrarse, pero es probable que el valor tenga poco significado para el usuario.

En el enrutamiento ASP.NET, se definen modelos de dirección URL que contienen marcadores de posición para los valores utilizados al administrar solicitudes URL. En tiempo de ejecución, las partes de la dirección URL que siguen al nombre de aplicación se analizan como valores discretos, tomando como base un modelo de dirección URL que haya definido. Por ejemplo, en la solicitud de https://server/application/Products/show/beverages, el analizador del enrutamiento puede pasar los valores Products, show y beverages a un controlador para la solicitud. Al contrario, en una solicitud que no administre el enrutamiento de direcciones URL, /Products/show/beverages se interpretaría como la ruta de acceso de un archivo de la aplicación.

También puede utilizar los modelos de dirección URL para crear mediante programación direcciones URL que corresponden a las rutas. Esto permite centralizar la lógica para crear hipervínculos en la aplicación ASP.NET.

Enrutamiento de ASP.NET frente a reescritura de direcciones URL

El enrutamiento de ASP.NET es diferente de otros esquemas de reescritura de direcciones URL. La reescritura de direcciones URL procesa las peticiones entrantes cambiando realmente la dirección URL antes de enviar la solicitud a la página web. Por ejemplo, una aplicación que utiliza la reescritura de direcciones URL podría cambiar una dirección URL de /Products/Widgets/ a /Products.aspx?id=4. Asimismo, la reescritura de direcciones URL normalmente no tiene una API para crear direcciones URL basadas en sus modelos. En la reescritura de direcciones URL, si cambia un modelo de dirección URL, deberá actualizar manualmente todos los hipervínculos que contengan la dirección URL original.

Con el enrutamiento de ASP.NET, la dirección URL no se cambia cuando se controla una solicitud entrante, porque el enrutamiento puede extraer valores de la dirección URL. Si tiene que crear una dirección URL, pase los valores del parámetro a un método que genere la dirección URL para usted. Para cambiar el modelo de dirección URL, cámbielo en una ubicación y todos los vínculos que cree en la aplicación basada en dicho modelo utilizarán automáticamente el nuevo modelo.

Definir rutas de dirección URL

Los modelos de dirección URL que se definen se conocen como rutas. En una ruta, se especifican marcadores de posición que se asignan a valores que se analizan de la solicitud URL. También se pueden especificar valores constantes que se utilizan para comparar solicitudes URL.

En una ruta, se definen marcadores de posición (denominados parámetros URL) encerrándolos entre corchetes ( { y } ). El carácter / se interpreta como un delimitador cuando se analiza la dirección URL. La información de la definición de la ruta que no es un delimitador y que no está encerrada entre corchetes se trata como un valor constante. Los valores que se extraen entre los delimitadores se asignan a marcadores de posición.

Puede definir más de un marcador de posición entre los delimitadores, pero deben ir separados por un valor constante. Por ejemplo, {language}-{country}/{action} es un modelo de ruta válido. Sin embargo, {language}{country}/{action} no es un modelo válido, porque no hay ninguna constante o delimitador entre los marcadores de posición. Por consiguiente, el enrutamiento no puede determinar dónde debe separar el valor del marcador de posición language del valor del marcador de posición country.

En la tabla siguiente se muestran modelos de ruta válidos y ejemplos de solicitudes URL que coinciden con los modelos.

Definición de la ruta

Ejemplo de dirección URL coincidente

{controlador}/{acción}/{id}

/Products/show/beverages

{tabla}/Details.aspx

/Products/Details.aspx

blog/{acción}/{entrada}

/blog/show/123

{tipo_informe}/{año}/{mes}/{día}

/sales/2008/1/5

{configuración regional}/{acción}

/en-US/show

{idioma}-{país}/{acción}

/en-US/show

Normalmente, se agregan rutas de un método que se llama desde el controlador del evento Application_Start en el archivo Global.asax. Este enfoque comprueba que las rutas están disponibles cuando se inicia la aplicación. También permite llamar directamente al método cuando se realiza una prueba unitaria de la aplicación. Si desea llamar directamente a un método al realizar una prueba unitaria de la aplicación, el método que registra las rutas debe ser estático (Shared en Visual Basic) y tener un parámetro RouteCollection.

Añada rutas agregándolas a la propiedad Routes estática de la clase RouteTable. La propiedad Routes es un objeto RouteCollection que almacena todas las rutas de la aplicación ASP.NET. En el ejemplo siguiente se muestra el código de un archivo Global.asax que agrega un objeto Route que define dos parámetros URL denominados action y categoryName.

Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)
    RegisterRoutes(RouteTable.Routes)
End Sub

Shared Sub RegisterRoutes(routes As RouteCollection)
    Dim urlPattern As String
    Dim categoryRoute As Route

    urlPattern = "Category/{action}/{categoryName}"
    categoryRoute = New Route(urlPattern, New CategoryRouteHandler)

    routes.Add(categoryRoute)
End Sub
protected void Application_Start(object sender, EventArgs e)
{
    RegisterRoutes(RouteTable.Routes);
}

public static void RegisterRoutes(RouteCollection routes)
{
    routes.Add(new Route
    (
         "Category/{action}/{categoryName}"
         , new CategoryRouteHandler()
    ));
}

Establecer los valores predeterminados de los parámetros de la ruta

Al definir una ruta, puede asignar un valor predeterminado a un parámetro. El valor predeterminado se utiliza si un valor de dicho parámetro no está incluido en la dirección URL. Establezca los valores predeterminados de una ruta asignando un diccionario a la propiedad Defaults de la clase Route. En el ejemplo siguiente se muestra una ruta con valores predeterminados.

Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)
    RegisterRoutes(RouteTable.Routes)
End Sub

Shared Sub RegisterRoutes(ByVal routes As RouteCollection)
    Dim urlPattern As String
    Dim categoryRoute As Route

    urlPattern = "Category/{action}/{categoryName}"
    categoryRoute = New Route(urlPattern, New CategoryRouteHandler)
    categoryRoute.Defaults = New RouteValueDictionary(New With _
        {.categoryName = "food", _
         .action = "show"} )

    routes.Add(categoryRoute)
End Sub
void Application_Start(object sender, EventArgs e) 
{
    RegisterRoutes(RouteTable.Routes);
}

public static void RegisterRoutes(RouteCollection routes)
{
  routes.Add(new Route
  (
     "Category/{action}/{categoryName}"
          new CategoryRouteHandler()
  )
    {
       Defaults = new RouteValueDictionary 
           {{"categoryName", "food"}, {"action", "show"}}
     }
  );
}

Cuando el enrutamiento de ASP.NET controla una solicitud URL, la definición de ruta mostrada en el ejemplo (con los valores predeterminados de food para categoryName y show para action) genera los resultados que se enumeran en la tabla siguiente.

dirección URL

Valores de parámetros

/Category

action = "mostrar" (valor predeterminado)

categoryName = "comida" (valor predeterminado)

/Category/add

action = "agregar"

categoryName = "comida" (valor predeterminado)

/Category/add/beverages

action = "agregar"

categoryName= "bebidas"

Administrar un número variable de segmentos

A veces tiene que controlar solicitudes URL que contienen un número variable de segmentos de dirección URL. Al definir una ruta, puede especificar que el último parámetro coincida con el resto de la dirección URL marcando el parámetro con un asterisco (*. Esto se conoce como un parámetro comodín. Una ruta con un parámetro comodín también coincidirá con las direcciones URL que no contienen ningún valor para el último parámetro. En el ejemplo siguiente se muestra un modelo de ruta que coincide con un número de segmentos desconocido.

query/{queryname}/{*queryvalues}

Cuando el enrutamiento de ASP.NET controla una solicitud URL, la definición de la ruta mostrada en el ejemplo genera los resultados que se enumeran en la tabla siguiente.

dirección URL

Valores de parámetros

/query/select/bikes/onsale

queryname = "select"

queryvalues = "bikes/onsale"

/query/select/bikes

queryname = "select"

queryvalues = "bikes"

/query/select

queryname = "select"

queryvalues = Cadena vacía

Agregar restricciones a las rutas

Además de comparar una solicitud URL con una definición de ruta por el número de parámetros de la dirección URL, puede especificar que los valores de los parámetros cumplan ciertas restricciones. Si una dirección URL contiene valores que están fuera de las restricciones de una ruta, esa ruta no se utiliza para administrar la solicitud. Agregue restricciones para asegurarse de que los parámetros URL contienen valores que funcionarán en la aplicación.

Las restricciones se definen utilizando expresiones regulares u objetos que implementan la interfaz IRouteConstraint. Al agregar la definición de la ruta a la colección Routes, agregue restricciones creando un objeto RouteValueDictionary que contenga la prueba de comprobación. A continuación, asigne este objeto a la propiedad Constraints . La clave del diccionario identifica el parámetro al que se aplica la restricción. El valor del diccionario puede ser o una cadena que representa una expresión regular o un objeto que implementa la interfaz IRouteConstraint.

Si proporciona una cadena, el enrutamiento trata la cadena como una expresión regular y comprueba si el valor del parámetro es válido llamando al método IsMatch de la clase Regex. La expresión regular siempre se trata sin distinción entre mayúsculas y minúsculas. Para obtener más información, vea Expresiones regulares de .NET Framework.

Si proporciona un objeto IRouteConstraint, el enrutamiento de ASP.NET comprueba si el valor del parámetro es válido llamando al método Match del objeto IRouteConstraint. El método Match devuelve un valor booleano que indica si el valor de parámetro es válido.

El ejemplo siguiente muestra restricciones que limitan qué valores se pueden incluir en los parámetros year y locale.

Shared Sub RegisterRoutes(ByVal routes As RouteCollection)
    Dim urlPattern As String
    Dim reportRoute As Route

    urlPattern = "{locale}/{year}"
    reportRoute = New Route(urlPattern, New ReportRouteHandler)
    reportRoute.Constraints = New RouteValueDictionary(New With _
        {.locale = "[a-z]{2}-[a-z]{2}", .year = "\d{4}"})

    routes.Add(reportRoute) 
End Sub
void Application_Start(object sender, EventArgs e) 
{
    RegisterRoutes(RouteTable.Routes);
}

public static void RegisterRoutes(RouteCollection routes)
{
    routes.Add(new Route
    (
      "{locale}/{year}"
         , new ReportRouteHandler()
    )
       {
          Constraints = new RouteValueDictionary 
          {{"locale", "[a-z]{2}-[a-z]{2}"},{year, @"\d{4}"}}
       });
}

Cuando el enrutamiento controla una solicitud URL, la definición de ruta mostrada en el ejemplo anterior genera los resultados que se enumeran en la tabla siguiente.

Dirección URL

Resultado

/en-US

Ninguna coincidencia. Se requieren las plantillas locale y year.

/en-US/08

Ninguna coincidencia. La restricción en year requiere 4 dígitos.

/en-US/2008

locale = "en-US"

year = "2008"

Escenarios a los que no se aplica el enrutamiento

De forma predeterminada, el enrutamiento no controla solicitudes que se asignan a un archivo físico existente en el servidor web. Por ejemplo, el enrutamiento no controla una solicitud de https://server/application/Products/Beverages/Coffee.aspx si existe un archivo físico en Products/Beverages/Coffee.aspx. El enrutamiento no controla la solicitud incluso aunque exista un modelo definido, como {controller}/{action}/{id}.

Si desea que el enrutamiento controle todas las solicitudes, incluso solicitudes que señalan a archivos, puede sobrescribir el comportamiento predeterminado estableciendo la propiedad RouteExistingFiles del objeto RouteCollection en true. Al establecer este valor en true, el enrutamiento controla todas las solicitudes que coincidan con un modelo definido.

También puede especificar que el enrutamiento no controle ciertas solicitudes URL. Para evitar que el enrutamiento controle ciertas solicitudes, defina una ruta y especifique que se debería usar la clase StopRoutingHandler para controlar dicho modelo. Cuando un objeto StopRoutingHandler controla una solicitud, el objeto StopRoutingHandler bloquea cualquier procesamiento adicional de la solicitud como una ruta. En lugar de esto, la solicitud se procesa como una página o servicio web ASP.NET, o como otro extremo ASP.NET. Por ejemplo, puede agregar la definición de ruta siguiente para evitar que el enrutamiento controle las solicitudes del archivo WebResource.axd.

Shared Sub RegisterRoutes(ByVal routes As RouteCollection)
    routes.Add(New Route("{resource}.axd/{*pathInfo}", New StopRouteHandler()))
End Sub
public static void RegisterRoutes(RouteCollection routes)
{
  routes.Add(new Route("{resource}.axd/{*pathInfo}", new StopRouteHandler()));
}

Cómo se comparan las direcciones URL con las rutas

Cuando el enrutamiento controla solicitudes URL, intenta comparar la dirección URL de la solicitud con una ruta. La comparación de una solicitud URL con una ruta depende de todas las condiciones siguientes:

  • Los modelos de ruta que ha definido o los modelos de ruta predeterminados, si los hubiera, incluidos en el tipo de proyecto.

  • El orden en que los agregó a la colección Routes.

  • Cualquier valor predeterminado que haya proporcionado para una ruta.

  • Cualquier restricción que haya proporcionado para una ruta.

  • Si ha definido el enrutamiento para controlar solicitudes que coinciden con un archivo físico.

Para evitar que el controlador equivocado administre una solicitud, debe tener en cuenta todas estas condiciones al definir rutas. El orden en que aparecen los objetos Route en la colección Routes es importante. La comparación de las rutas se realiza desde la primera a la última ruta de la colección. Cuando existe una coincidencia , no se evalúan más rutas. En general, agregue rutas a la propiedad Routes en orden de más específica a menos específica para las definiciones de ruta.

Por ejemplo, suponga que agrega rutas con los modelos siguientes:

  • Ruta 1: {controller}/{action}/{id}

  • Ruta 2: products/show/{id}

La Ruta 2 nunca controlará una solicitud porque se evalúa primero la Ruta 1, y siempre coincidirá con solicitudes que también podrían funcionar para la Ruta 2. Una solicitud de https://server/application/products/show/bikes parece coincidir con más exactitud con la Ruta 2, pero la Ruta 1 se controla con los siguientes valores:

  • controller = productos

  • action = mostrar

  • id = bicicletas

Se utilizan los valores predeterminados si falta un parámetro en la solicitud. Por consiguiente, pueden hacer que una ruta coincida con una solicitud inesperada. Por ejemplo, suponga que agrega rutas con los modelos siguientes:

  • Ruta 1: {report}/{year}/{month}, con los valores predeterminados de year y month.

  • Ruta 2: {report}/{year}, con el valor predeterminado de year.

La Ruta 2 nunca controlará una solicitud. La Ruta 1 podría estar destinada a un informe mensual y la Ruta 2 podría estar destinada a un informe anual. Sin embargo, los valores predeterminados de la Ruta 1 significan que coincidirá con cualquier solicitud que pueda funcionar también para la Ruta 2.

Puede evitar la ambigüedad de los modelos incluyendo constantes, como annual/{report}/{year} y monthly/{report}/{year}/{month}.

Si una dirección URL no coincide con ningún objeto Route definido en la colección RouteTable, el enrutamiento de ASP.NET no procesará la solicitud. En lugar de esto, el procesamiento se pasa a una página ASP.NET, servicio web u otro extremo ASP.NET.

Crear direcciones URL a partir de rutas

Puede utilizar rutas para generar direcciones URL si desea centralizar la lógica para crear direcciones URL. Una dirección URL se crea pasando valores de parámetro como un diccionario al método GetVirtualPath del objeto RouteCollection. El método GetVirtualPath busca la primera ruta del objeto RouteCollection que coincide con los parámetros del diccionario. La ruta coincidente se utiliza para generar la dirección URL. En el ejemplo siguiente se muestra una definición de ruta.

Shared Sub RegisterRoutes(ByVal routes As RouteCollection)
    routes.Add(New Route( _
      "Category/{action}/{categoryName}", _
      New RouteValueDictionary(New With _
          {.categoryName = "food", _
           .action = "show"}), _
           New CategoryRouteHandler()) )
End Sub
public static void RegisterRoutes(RouteCollection routes)
{
  routes.Add(new Route
  (
     "Category/{action}/{categoryName}"
          new CategoryRouteHandler()
  )
    {
       Defaults = new RouteValueDictionary {{"categoryName", "food"}, 
           {"action", "show"}}
     }
  );
}

En el ejemplo siguiente se muestra un control que crea una dirección URL basada en la ruta.

Dim urlParameters As RouteValueDictionary

urlParameters = New RouteValueDictionary(New With {.categoryName = "beverages", _
        .action = "summarize"})
HyperLink1.href = RouteTable.Routes.GetVirtualPath _
    (context, urlParameters).VirtualPath
HyperLink1.href = RouteTable.Routes.GetVirtualPath
  (context,
  new RouteValueDictionary { 
    { "categoryName", "beverages" }, 
    {"action", "summarize" }}
  ).VirtualPath;

Cuando se ejecuta este código, el control HyperLink1 contendrá el valor "Category/summarize/beverages" de la propiedad href.

Al crear una dirección URL a partir de una ruta, puede especificar qué ruta se debe utilizar incluyendo un nombre para la ruta. Para obtener más información, vea Cómo: Crear una dirección URL a partir de una ruta.

Vea también

Conceptos

Introducción a la infraestructura de ASP.NET