route net mvc examples asp .net asp.net asp.net-mvc routing asp.net-routing

.net - net - route controller c#



¿Cómo enrutar URL estructuradas por árbol con enrutamiento ASP.NET? (4)

Me gustaría lograr algo muy similar a esta pregunta , con algunas mejoras.

Hay una aplicación web ASP.NET MVC.

Tengo un árbol de entidades.
Por ejemplo, una clase de Page que tiene una propiedad llamada Niños, que es de tipo IList<Page> . (Una instancia de la clase Page corresponde a una fila en una base de datos).

Tenga en cuenta que los propietarios del sitio pueden agregar una nueva página en cualquier momento, o eliminar las existentes, y las URL también deben reflejar esos cambios.

Me gustaría asignar una URL única a cada Page en la base de datos.
PageController objetos de la Page con un controlador llamado PageController .

Ejemplo de URL:

http://mysite.com/Page1/ http://mysite.com/Page1/SubPage/ http://mysite.com/Page/ChildPage/GrandChildPage/

Te dan la imagen.
Por lo tanto, me gustaría que cada objeto de la Page tenga su propia URL que sea igual a la URL de su padre más su propio nombre.
Además de eso, también me gustaría la capacidad de asignar una sola Page a la URL / (raíz).

Me gustaría aplicar estas reglas:

  1. Si una URL puede manejarse con cualquier otra ruta, o si existe un archivo en el sistema de archivos en la URL especificada, permita que ocurra la asignación de URL predeterminada
  2. Si el proveedor de ruta virtual puede manejar una URL, déjalo que la maneje
  3. Si no hay otro, correlacione las otras URL con la clase PageController

También encontré esta pregunta , y también esta y esta , pero no fueron de mucha ayuda, ya que no brindan una explicación sobre mis dos primeros puntos.

Veo las siguientes soutions posibles:

  • Mapa de una ruta para cada página invidually.
    Esto requiere que revise todo el árbol cuando se inicia la aplicación y agrega una ruta de coincidencia exacta al final de la tabla de rutas.
  • Podría agregar una ruta con {*path} y escribir un IRouteHandler personalizado que lo maneje, pero no veo cómo podría lidiar con las dos primeras reglas, ya que este manejador manejaría todo.

Hasta ahora, la primera solución parece ser la correcta, porque también es la más simple. Pero aún así, incluso en ese caso, no estoy seguro de cómo puedo hacer que PageController maneje las solicitudes.

Realmente apreciaría tus pensamientos sobre esto.

¡Gracias de antemano!

EDITAR: Ahora tuve tiempo de examinar cada aspecto de cada respuesta que recibí. Acepté la respuesta de Neal, ya que él es quien brinda la mejor explicación sobre cómo funcionan las cosas. También volví a votar todas las demás respuestas, ya que proporcionan buenas ideas.


Una idea diferente es usar T4 (Text Template Transformation Toolkit) para leer a sus hijos una vez y generar el contenido de su archivo Global.asax.

EDITAR: Básicamente con T4 puede automatizar la generación de archivos de texto. Por ejemplo, en lugar de copiar elementos de una gran colección y pegarlos con un contexto específico en un archivo de texto (como INSERT INTO [MyTable] (Text) VALUES (@ItemText) ) podría hacer que un motor T4 lea la colección y genera estas instrucciones de inserción para ti. Es estático y no está diseñado para un tiempo de ejecución.

Encuentro que hay una muy buena introducción disponible en el libro Pro Entity Framework 4.0 .

Pero si dices que necesitas hacerlo de forma dinámica, esta puede no ser la herramienta para ti.


Usted sabe la estructura de sus páginas cuando guarda la página. Por lo tanto, puede generar una URL para cada página y guardarla en el registro de la base de datos. Luego puede usar la regla {*path} y encontrar la coincidencia exacta en la base de datos. Esta regla debe ser la última en la definición de sus reglas, por lo que puede hacer coincidir otras rutas.

Por ejemplo, su Page1 no tiene página primaria, su url es Page1 . Su SubPage sabe que es padre, por lo que puede aumentar la URL de la Página1 Page1/SubPage etc.


Puede usar un patrón de "Page/{*path}" . Luego puede descomponer la ruta dividiendo la cadena en ''/'' y recorrerla, o puede usar la sugerencia de Rarouš de almacenar la ruta [generada] en el DB y hacer una búsqueda directa.

Si usa el método de Rarouš, deberá actualizar las entradas de ruta en su tabla para todos los elementos secundarios cuando la ruta principal cambie. Esto se puede hacer simplemente con una sola consulta de actualización.

Supongo que está mapeando la página que desea utilizar para la página de inicio en algún lugar de un archivo de configuración o entrada de tabla. Puede hacer que el controlador de la página de inicio realice la búsqueda y devuelva el contenido de la vista de la página de inicio para procesar (puede usar una vista compartida, una vista parcial o una llamada al controlador de página para no duplicar el comportamiento) o puede hacer que lo redirija a esa página.

Usando esta técnica, puede tener un controlador de página única y una vista que maneje todas estas páginas de la misma manera. Sus otros requisitos parecen ser manejados automáticamente por el marco MVC.

Tu camino se vería así:

http://mysite.com/Page/Page1/ http://mysite.com/Page/Page1/SubPage/ http://mysite.com/Page/Page/ChildPage/GrandChildPage/

Por supuesto, puede usar un prefijo que no sea "Página".


Las rutas se procesan en el orden en que se agregan a la colección. Puede agregar su ruta personalizada después de las rutas existentes para asegurarse de que sea la última en tener la oportunidad de manejar la solicitud. Esto le permitirá agregar rutas para archivos existentes (virtuales o de otro tipo) antes que él y, por lo tanto, cumplir los criterios 1 y 2.

De forma predeterminada, el enrutamiento MVC enrutará a los archivos existentes antes de aplicar cualquier ruta almacenada en la colección de ruta; vea http://msdn.microsoft.com/en-us/library/system.web.routing.routecollection.routeexistingfiles.aspx . (Hattip a Paul - ver comentarios).

Para enrutar las solicitudes a su controlador de página, simplemente cree una ruta personalizada que examine la ruta virtual y, si coincide con el patrón de una página en la base de datos, devuelve el RouteData . Configure su RouteData con los valores apropiados extraídos de la ruta virtual (por ejemplo, establezca la clave de ruta en / Parent / Child / Grandchild), establezca la clave del controlador en el nombre del controlador de página (por ejemplo, Página) y la acción en el nombre de la acción que desea ejecutar (por ejemplo, Mostrar). El RouteData debe crear con MvcRouteHandler (no estoy seguro de si ese es el nombre de clase correcto).

Para garantizar que las URL de las páginas controladas por la base de datos se devuelvan correctamente, anule el GetVirtualPath( RequestContext, RouteValueDictionary ) de RouteBase y utilice los valores de ruta pasados ​​para determinar si esta es una página manejada por la base de datos y si es necesario crear la ruta virtual. (o devuelve null de lo contrario).

Para obtener ayuda con la anulación de GetRouteData y GetVirtualPath , observe el código fuente reflejado de System.Web.Routing.RouteBase y System.Web.Routing.Route ; después de eso Google es tu amigo.

Las rutas se usan en reversa para determinar la URL dada al controlador, a la acción y a cualquier otro valor de ruta. Debería poder utilizar esto para construir la url de la página dentro del contexto que se solicita.