asp.net mvc routing - net - Cómo evitar que Url.RouteUrl(...) herede valores de ruta de la solicitud actual
route controller c# (2)
Mi solución fue esta:
Un método de ayuda HtmlExtension:
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 sé con certeza que siempre se comportará de la misma manera sin importar el contexto.
La forma en que funciona es tomar el UrlHelper
existente y crear uno nuevo con ''RouteData'' en blanco. Esto significa que no hay nada de lo que heredarse (incluso un valor nulo).
Digamos que tiene un método de acción para mostrar productos en un carrito de compras
// ProductsController.cs
public ActionMethod Index(string gender) {
// get all products for the gender
}
En otros lugares, en una cabecera que se muestra en cada página, está utilizando Url.RouteUrl
para crear enlaces HREF a otras páginas del sitio:
<a href="<%= Url.RouteUrl("testimonials-route", new { }) %>" All Testimonials </a>
Esta testimonials-route
se define en global.ascx
por la primera ruta a continuación. Observe que la llamada anterior a RouteUrl
no proporciona un gender
, pero la ruta se define con un valor predeterminado de ''neutral'', por lo que esperamos que se llame a 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 para /testimonials/women
Si alguien visita la página /products
entonces obtenemos un HREF vacío (la llamada a RouteUrl devuelve null).
Pero eso no tiene sentido, ¿verdad? testimonials-route
se supone que debe ser ''neutral''
para nosotros si no le proporcionamos un valor de ruta.
Lo que sucede es que la extensión de ayuda Url.RouteUrl(routeName, routeValues)
primero buscará en su parámetro routeValues
un valor de ruta de gender
y, si no lo encuentra en ese diccionario, verá la URL actual que nosotros '' re on (recuerde que Url es un objeto UrlHelper que tiene el contexto de la solicitud actual disponible).
Esto puede tener un buen efecto 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 especificamos explícitamente ''neutral'' como predeterminado en el archivo global.asax.cs
.
En el caso en el que visitamos /products/
activamos la ''products-route''
y se llamó al método Products(null)
. La llamada a Url.RouteUrl()
realidad hereda ESTE valor nulo para el gender
cuando estamos creando una URL usando testimonials-route
. Aunque hemos especificado un valor predeterminado para el gender
en ''testimionials-route
'', todavía utiliza este valor nulo, lo que hace que la ruta falle y RouteUrl
devuelva null. [nota: la ruta falla porque tenemos una restricción en (men | women | neutral) y null no se ajusta a eso]
En realidad, se vuelve más aterrador: en ese ''controlador'' y ''acción'' se pueden heredar de la misma manera. Esto puede hacer que las URL se generen completamente en el controlador incorrecto, 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 hayas resuelto, puedes solucionarlo fácilmente de muchas maneras, pero en otros casos podría causar un comportamiento peligroso. Esto puede ser por diseño, pero definitivamente es aterrador.
Tal vez me esté perdiendo algo aquí, pero ¿por qué no configurarlo así?
En su asax global, cree 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" }
);
Luego, use 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" }) %>
Que, en mi máquina se resuelve a las siguientes urls:
/Testimonials/Neutral
/Testimonials/Male
/Testimonials/Female
No estoy seguro de si esta es una solución aceptable, pero es una alternativa, ¿no?