2009-07-18 13 views
30

Digamos que tiene un método de acción para mostrar los productos en un carrito de la compraCómo prevenir Url.RouteUrl (...) de heredar los valores de ruta de la petición actual

// ProductsController.cs 
public ActionMethod Index(string gender) { 

     // get all products for the gender 
} 

Por otra parte, en un mástil que es que aparece en cada página que está utilizando Url.RouteUrl para crear enlaces HREF a otras páginas en el sitio:

<a href="<%= Url.RouteUrl("testimonials-route", new { }) %>" All Testimonials </a> 

Este testimonials-route se define en global.ascx por la primera ruta a continuación. Observe que la llamada anterior al RouteUrl no proporciona un gender, pero la ruta se define con un valor predeterminado de 'neutral', por lo que esperaríamos que se llamara Testimonials.Index ("neutral").

routes.MapRoute(
    "testimonials-route", 
    "testimonials/{gender}", 
    new { controller = "Testimonials", action = "Index", gender = "neutral" }, 
    new { gender = "(men|women|neutral)" } 
); 

routes.MapRoute(
    "products-route", 
    "products/{gender}", 
    new { controller = "Products", action = "Index", gender = (string)null }, 
    new { gender = "(men|women|neutral)" } 
); 

Si alguien visita la página /products/women obtenemos un HREF a /testimonials/women Si alguien visita la página /products entonces tenemos un HREF vacía (la llamada a RouteUrl devuelve un valor nulo).

Pero eso no tiene sentido, ¿verdad? testimonials-route se supone que es el predeterminado para nosotros 'neutral' si no proporcionamos un valor de ruta para el mismo?

lo que resulta que está sucediendo es que Url.RouteUrl(routeName, routeValues) extensión ayudante primero buscará en su parámetro routeValues por un valor gender ruta y si no lo encuentra en ese diccionario que se verá en la URL actual que estamos en (recuerde que Url es un objeto UrlHelper que tiene el contexto de la solicitud actual disponible).

Esto tiene un posible efecto agradable de darnos un enlace a los testimonios de los hombres si estamos en una página de productos para hombres, pero eso probablemente no es lo que queremos si no hemos pasado un valor en la llamada RouteUrl, y explícitamente se especificó 'neutral' como predeterminado en el archivo global.asax.cs.

En el caso en que visitamos /products/ activamos la ruta 'products-route' y se llamó al método Products(null). La llamada al Url.RouteUrl() en realidad hereda ESTE valor nulo para gender cuando estamos creando una URL usando testimonials-route. Aunque hemos especificado un valor predeterminado para gender en 'testimionials-route ', todavía utiliza este valor nulo que hace que la ruta falle y RouteUrl devuelve nulo. [nota: la ruta falla porque tenemos una restricción en (hombres | mujeres | neutro) y nulo no cabe eso]

En realidad se pone más atemorizante - en ese 'controlador' y 'acción' se puede heredar de la misma manera. Esto puede conducir a que se generen direcciones URL completamente equivocadas en el controlador incluso cuando se llama a RouteUrl (...) con un nombre de ruta explícito que tiene un controlador predeterminado.

En este caso, una vez que lo ha resuelto, puede solucionarlo con bastante facilidad de muchas maneras, pero en otros casos podría causar un comportamiento peligroso. Esto puede ser por diseño, pero definitivamente da miedo.

+0

agregando un bounty un año y medio después de la pregunta original porque (a) me gustaría saber si el marco ahora lo hace por mí y (b) tengo mucha curiosidad por qué esto solo tiene 2 votos positivos. pensé que sería un problema común, ¡así que me pregunto si estoy haciendo algo mal! –

+0

esto estaba pateando mi botín, ya que la etiqueta {domain} carecía de un valor, pero que el sistema debería proporcionar automáticamente. Una vez que cambié esto, funcionó. –

+0

¿por qué no simplemente llama a RenderUrl como: ' "' - entonces, nada se sobrescribe . – Gerwald

Respuesta

26

Mi solución fue la siguiente:

Un método HtmlExtension ayudante:

public static string RouteUrl(this UrlHelper urlHelper, string routeName, object routeValues, bool inheritRouteParams) 
    { 
     if (inheritRouteParams) 
     { 
      // call standard method 
      return urlHelper.RouteUrl(routeName, routeValues); 
     } 
     else 
     { 
      // replace urlhelper with a new one that has no inherited route data 
      urlHelper = new UrlHelper(new RequestContext(urlHelper.RequestContext.HttpContext, new RouteData())); 
      return urlHelper.RouteUrl(routeName, routeValues); 
     } 
    } 

ahora puedo hacer:

Url.RouteUrl('testimonials-route', new { }, false) 

y saber con seguridad que siempre se comportará de la misma manera sin importar cual es el contexto

La manera en que funciona es tomar el UrlHelper existente y crear uno nuevo con el 'RouteData' en blanco. Esto significa que no hay nada de lo que heredarse (incluso un valor nulo).

+0

si bien estoy de acuerdo con mi solución, ojalá hubiera una forma de aplicarla globalmente, y no tener que recordar usar siempre esta sobrecarga. con suerte MVC4 le dará un mayor control sobre esto. –

+0

Acabo de encontrar exactamente el mismo problema. ¡Esto fue muy útil! Estaba pensando en extender el método HtmlHelper.RouteLink para hacer lo mismo para los enlaces, pero tengo problemas para resolver la sintaxis para crear un nuevo HtmlHelper. – goombaloon

+0

Esta es una buena solución. Para nosotros, todos estos enlaces estaban en la misma vista parcial, así que solo instalé el nuevo UrlHelper como una variable y usé esa variable en la propiedad parcial UrlHelper estándar. –

2

Tal vez me estoy perdiendo algo aquí, pero por qué no configurarlo de la siguiente manera:

En su GLOBAL.ASAX, crear dos rutas:

routes.MapRoute(
    "testimonial-mf", 
    "Testimonials/{gender}", 
    new { controller = "Testimonials", action = "Index" } 
); 

routes.MapRoute(
    "testimonial-neutral", 
    "Testimonials/Neutral", 
    new { controller = "Testimonials", action = "Index", gender="Neutral" } 
); 

A continuación, utilice Url.Action en lugar de URL .RouteUrl:

<%= Url.Action("Testimonials", "Index") %> 
<%= Url.Action("Testimonials", "Index", new { gender = "Male" }) %> 
<%= Url.Action("Testimonials", "Index", new { gender = "Female" }) %> 

Lo cual, en mi máquina resuelve a las siguientes direcciones:

/Testimonials/Neutral 
/Testimonials/Male 
/Testimonials/Female 

No estoy seguro si esta es una solución aceptable, pero es una alternativa, ¿no?

+0

desafortunadamente (¡o afortunadamente quizás!) El problema no está en el análisis sintáctico y el enrutamiento de la URL. eso funciona perfectamente como se esperaba, por lo que su primera ruta aquí es suficiente (si agrega un parámetro predeterminado). está en la creación real de la URL cuando los valores de ruta existentes se heredan inesperadamente. mi solución que he estado usando durante más de un año; es simplemente molesto cuando necesitas usar otras sobrecargas de RouteUrl o RouteLink y necesitas crear una tonelada de sobrecargas de métodos. gracias por la respuesta –

Cuestiones relacionadas