La tabla de rutas en el framework ASP.NET MVC sirve para mapear las URLs de la aplicación a sus correspondientes controladores y acciones dentro de ellos.
Lo que mucha gente no sabe es que eso no es realmente una convención del framework de ASP.NET MVC ni mucho menos una obligación. Que las URLs sigan por defecto esta forma se debe, ni más ni menos, al código que nos genera por defecto Visual Studio cuando creamos un proyecto ASP.NET MVC. La responsable de decidir qué acción de qué controlador se encarga de procesar cada petición es la tabla de rutas y es de lo que vamos a hablar hoy.
Hablando rápidamente podríamos decir que la tabla de rutas es la responsable de mapear cada URL a una acción de un controlador. La frase puede parecer baladí, pero no lo es en absoluto. Hay dos aspectos clave a tener en cuenta:
- Cada URL debe ser mapeada a una acción de un controlador en concreto.
- Para mapear una petición del navegador a una acción de un controlador se usa sólo la URL. Repito: sólo la URL.
Lo que nos lleva a preguntarnos, que son los valores de ruta.
Valores de ruta (route values)
Los valores de ruta no son más que un conjunto de valores (parámetros si preferís) cuyo valor se extrae a partir de la petición que realiza el navegador, concretamente a partir de la URL. Puede haber todos los valores de ruta que se quiera, pero hay dos que deben ser establecidos siempre por cada URL:- controller: Debe contener el nombre del controlador que gestionará la petición
- action: Debe contener el nombre de la acción que gestionará la petición
La tabla de rutas es pues la responsable de, decidir, por cada URL, que valores de ruta, y con qué valor real, se rellenan. Recordad que controller y action son obligatorios y que son usados por el framework para, precisamente, decidir qué acción de qué controlador gestiona la petición, de ahí que se diga comúnmente, que la tabla de rutas mapea URLs a acciones, aunque como hemos visto, realmente hace algo más.
Configuración de la tabla de rutas
La tabla de rutas no tiene valores por defecto. Es decir, inicialmente está vacía y eso significa que no hay ninguna petición que se pueda enrutar. Es el propio Visual Studio, quien nos genera código para configurar la tabla de rutas, con unos valores iniciales. Y esos valores son los que hacen que las URLs tengan la forma conocida de http://servidor/controlador/accion. Si abrís Visual Studio y creáis un proyecto ASP.NET MVC nuevo (incluso si elegís la opción de Empty), veréis el siguiente código en el archivo Global.asax.cs:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
}
Este código es el que configura la tabla de rutas. El parámetro routes que recibe este método es la propia tabla de rutas, que está en la propiedad estática Routes de la clase RouteTable.
Analicemos este código, y empecemos no por la primera línea, sino por la segunda: la que llama al método MapRoute. Este método (que es realmente un método de extensión, aunque esto no sea relevante) nos permite añadir una nueva entrada a la tabla de rutas de forma sumamente sencilla. Está sobrecargado pero en este código los parámetros que recibe son:
- El nombre de la ruta (un identificador de la ruta). En este caso la ruta se llama Default
- Las URLs que mapea esta ruta
- Los valores por defecto de los valores de ruta, en caso de no ser encontrados en la URL.
Patrones de URLs
Centrémonos un poco en segundo parámetro. Su valor es {controller}/{action}/{id}. Eso es simplemente el patrón que deben cumplir las URLs para ser procesadas por esta ruta. Lo que está entre llaves es el nombre del valor de ruta que se crea. Así pues el patrón {controller}/{action}/{id} mapeará cualquier URL que esté en la forma http://servidor/xxx/yyy/zzz. Y además asignará los siguientes valores de ruta:- controller = xxx
- action = yyy
- id = zzz
Valores por defecto
El tercer parámetro de MapRoute son los valores por defecto de los valores de ruta. Es decir, si el valor de ruta no puede sacarse a partir del patrón de URL especificado, se asumirá dicho valor. Se define como un objeto anónimo cuyas propiedades tienen el nombre de los valores de ruta y el valor de dicha propiedad es el valor por defecto del valor de ruta. En nuestro caso está definido como:new { controller = "Home", action = "Index", id = UrlParameter.Optional }
Por lo tanto tenemos que:
- El valor de ruta controller vale Home por defecto.
- El valor de ruta action vale Index por defecto
- El valor de ruta id es opcional. Es decir si no aparece no se creará (no existirá). No es que valga null, 0, cadena vacía o cualquier otro valor vacío, no. Simplemente no se creará.
- http://servidor/Books/View/10 se procesará y los valores de ruta serán
- controller = Books
- action = View
- id = 10
- http://servidor/Books se procesará y los valores de ruta serán
- controller = Books
- action = Index (valor por defecto)
- id = No existirá el valor de ruta id
- http://servidor se procesará y los valores de ruta serán
- controller = Home (valor por defecto)
- action = Index (valor por defecto)
- id = No existirá el valor de ruta id
- http://servidor/Books/View/10/20 No será procesada por la tabla de rutas. Esta URL no puede mapearse al patrón {controller}/{action}/{id}
Múltiples patrones
La tabla de rutas se llama precisamente tabla porque puede contener varias entradas (es decir, varios patrones de URL, con sus parámetros por defecto, etc). Para añadir más entradas (rutas, cada entrada se conoce como ruta), lo más sencillo es añadir llamadas a MapRoute. P.ej. si quisiéramos procesar la URL anterior http://servidor/Books/View/10/20 podríamos añadir una entrada adicional:
routes.MapRoute(
"DosIds", // Route name
"{controller}/{action}/{id}/{id2}"
);
- controller = Books
- action = View
- id = 10
- id2 = 20
routes.MapRoute(
"ViewProfile", // Nombre de la ruta
"Ver/{author}", // URL with parameters
new { controller = "Profile", action = "View" }
);
Un detallito a tener en cuenta de esta nueva entrada es que dado que no hay lugar en el patrón de URL para los valores de ruta de controller y action, al ser esos obligatorios, deben especificarse como valores por defecto.
Esta entrada mapea una URL del tipo: http://servidor/Ver/Edu con los valores de ruta:
- controller = Profile (valor por defecto)
- action = View (valor por defecto)
- author = Edu (sacado del patrón de la URL)
¿Por qué?
Pues simplemente porque la tabla de rutas se evalúa en orden. Y ¿puede mapear la primera entrada (la ruta llamada Default) una URL del tipo http://servidor/Ver/Edu? La respuesta es que sí, y los valores de ruta quedan establecidos a:
- controller = Ver
- action = Edu
- id = No hay valor de ruta id (recordad que era opcional)
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"ViewProfile", // Nombre de la ruta
"Ver/{author}", // URL with parameters
new { controller = "Profile", action = "View" }
);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new {controller = "Home", action = "Index", id = UrlParameter.Optional} // Parameter defaults
);
}
Ignorar patrones de URL
A veces es necesario que ciertas peticiones con una determinada URL, no sean gestionadas por el framework de ASP.NET sino por el propio motor de ASP.NET o bien el propio IIS. Un ejemplo podría ser una petición a una imagen. En este caso, no vamos a querer un controlador que nos devuelva la imagen, es mucho mejor dejar que sea el propio IIS quien lo haga (será mucho más eficiente). Por ello el framework permite definir rutas de exclusión, es decir rutas que si mapean una determinada URL, dicha petición será ignorada por ASP.NET MVC.Para crear esas rutas especiales, se usa el método IgnoreRoute. Se le suele pasar un solo argumento, que es el patrón de URL a ignorar. Un ejemplo lo tenemos en el propio código que genera Visual Studio:
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
Este patrón de URL se mapeará a todas aquellas URLs que tengan la forma http://servidor/xxx.axd/yyy
Dónde:
- xxx es cualquier nombre
- yyy es cualquier cosa, incluyendo barras separadoras (/). El hecho de que yyy pueda incluir barras separadoras es porque se usa la forma {*nombre_valor_ruta} (con un asterisco) que es lo que se conoce como catch-all y significa literalmente: captura todos los caracteres de la URL que vengan a partir de ahora.
En el siguiente artículo vamos a ver los valores de ruta y los controladores.
Eduard Tomàs
Apasionado de la informática, los videojuegos, rol y... la cerveza. Key Consulta...