examples - ASP.NET MVC Url.Action agrega valores de ruta actuales a la URL generada
route controller c# (7)
Aquí hay una solución alternativa que no requiere el enrutamiento de atributos, ni altera los valores de ruta actuales dentro de su solicitud. Esta idea proviene de http://notherdev.blogspot.ca/2013/10/aspnet-mvc-current-values-used-by-url-action.html , que modifiqué ligeramente para que funcione sin MvcFutures.
Construí mi propia extensión de Action
en UrlHelper con un bool adicional que le permite ignorar opcionalmente los valores de ruta actuales (para no entrar en conflicto con los métodos de acción existentes en UrlHelper).
Lo que hace es construir un RequestContext completamente nuevo del actual, usando la ruta actual pero no los valores de ruta actuales. Luego pasamos eso a los ayudantes de base. De esta forma, cuando los ayudantes básicos van a ver cuáles son los valores de ruta dentro del contexto de solicitud, no encontrarán ninguno y, por lo tanto, no los usarán al generar la URL.
public static string Action(this UrlHelper urlHelper, string actionName, string controllerName, object routeValues, bool ignoreCurrentRouteValues=false) {
var routeValueDictionary = new RouteValueDictionary(routeValues);
var requestContext = urlHelper.RequestContext;
if (ignoreCurrentRouteValues) {
var currentRouteData = requestContext.RouteData;
var newRouteData = new RouteData(currentRouteData.Route, currentRouteData.RouteHandler);
requestContext = new RequestContext(requestContext.HttpContext, newRouteData);
}
return UrlHelper.GenerateUrl(null, actionName, controllerName, routeValueDictionary,
urlHelper.RouteCollection, requestContext, includeImplicitMvcValues: false);
}
He visto esta pregunta un par de veces aquí en SO, pero ninguna con una respuesta aceptable:
ASP.NET MVC @ Url.Action incluye datos de ruta actuales
ASP.NET MVC agrega implícitamente valores de ruta
Básicamente tengo un controlador con un método de acción llamado Grupo, tiene una sobrecarga que no recibe parámetros y muestra una lista de elementos y otro que recibe una identificación y muestra detalles para ese grupo.
Si hago algo como esto:
Url.Action("Group", "Groups");
Desde la página principal del sitio (/) devuelve una URL como esta:
"mysite.com/Groups/Group"
lo cual está bien Ahora, si la dirección actual del sitio es / Grupos / Grupo / 1 Y llamo al mismo método
Url.Action("Group", "Groups");
la url devuelta es esta:
"mysite.com/Groups/Group/1"
Agrega automáticamente el valor de la ruta para la página actual al generar la URL. Incluso si genero la URL de esta manera:
Url.Action("Group", "Groups", null);
Especificando explícitamente que no quiero ningún valor de ruta, la URL generada es la misma. Para obtener la dirección que quiero, tengo que establecer explícitamente el valor de la ruta en una cadena vacía, así:
Url.Action("Group", "Groups", new {id=""});
Esto generará la siguiente url:
"mysite.com/Groups/Group"
Mi pregunta es, ¿por qué sucede esto? Si no configuro ningún valor de ruta, no debería agregarlos a la URL generada.
Ejemplo simple:
public class ProductController : Controller
{
public ActionResult Edit(int id)
{
return View();
}
[Route("Product/Detail/{id:int}")]
public ActionResult Detail(int id)
{
return View();
}
}
La vista de edición contiene solo esto:
@{ Layout = null;}
@Url.Action("Detail", "Cmr")
Así que cuando ejecutas tu sitio, por ejemplo, localhost:randomPort/Product/Edit/123
, obtienes la siguiente respuesta: /Product/Detail/123
¿Por qué? Debido a que el atributo de Route
ha requerido el id
parámetro. El parámetro Id se lee desde url, aunque solo Url.Action(methodName, controller)
- sin especificar el parámetro. Además, no tiene sentido tener un detalle de método sin identificación.
Para que los atributos funcionen, la siguiente línea debe agregarse a RouteConfig.cs
:
public static void RegisterRoutes(RouteCollection routes)
{
...
routes.MapMvcAttributeRoutes();
...
}
Entonces, cuando leí la respuesta de Objectbox, pensé que tendría que modificar varios enlaces en mi código. Luego intenté agregar una ruta predeterminada omitiendo los parámetros predeterminados que resolvieron el problema:
routes.MapRoute(
"ArtistArtworkDefPage",
"Artist/{username}/Artwork",
new
{
controller = "Artist",
action = "Artwork",
page = 1
}
);
routes.MapRoute(
"ArtistArtwork",
"Artist/{username}/Artwork/{page}",
new
{
controller = "Artist",
action = "Artwork",
page = 1
},
new { page = @"/d+" }
);
Mi aplicación establece explícitamente valores de ruta y no quiere un valor mágico de la solicitud actual. Quiero tener el control total
He hecho una extensión que coexiste con la colección de mi biblioteca de rutas. De ahí el único parámetro RouteValueDictionary. (Ver mi comentario de la biblioteca de ruta en la parte inferior)
Aquí elimino cualquier valor de ruta de la solicitud antes de generar una url.
(Nota: para la matriz. contiene la parte ignorecase, ver: ¿Cómo puedo hacer que Array.Contains distinga entre mayúsculas y minúsculas en una matriz de cadenas? )
public static string Action(this UrlHelper helper,
RouteValueDictionary routeValues)
{
RemoveRoutes(helper.RequestContext.RouteData.Values);
string url = helper.Action(routeValues["Action"].ToString(), routeValues);
return url;
}
public static void RemoveRoutes(RouteValueDictionary currentRouteData)
{
List<string> keyList = new List<string>(currentRouteData.Keys);
string[] ignore = new[] { "Area", "Controller", "Action" };
foreach (string key in keyList)
{
if (!ignore.Contains(key, StringComparer.CurrentCultureIgnoreCase))
currentRouteData.Remove(key);
}
}
Tengo métodos de extensión FormLink y ActionLink que utilizan el método RemoveRoutes. Ningún asistente en mi biblioteca mvc utiliza un método que no es un método de extensión que he creado. De esta manera, todos los datos de ruta se limpian antes de generar urls.
Como referencia, uso AttributeRouting. Aquí hay un ejemplo de una ruta de mi biblioteca de rutas.
public static RouteValueDictionary DisplayNews(int newsId)
{
RouteValueDictionary route = new RouteValueDictionary();
route["Area"] = _area;
route["Controller"] = _controller;
route["Action"] = "DisplayNews";
route["newsId"] = newsId;
return route;
}
Una solución simple sería primero llamar
Url.Action("dummy", new { ... })
y luego cambie el nombre del maniquí en la cadena resultante por el nombre de la acción correcta.
Una solución tonta encontré que funciona para manejar los datos de enrutamiento de la página actual, incluido el cambio del parámetro de la página según tus preferencias
@{
var current_route_1 = new RouteValueDictionary(Url.RequestContext.RouteData.Values);
var current_route_2 = new RouteValueDictionary(Url.RequestContext.RouteData.Values);
//If you want to customize the routing values
current_route_1["controller"] = "Controller1";
current_route_2["controller"] = "Controller2";
}
@Url.RouteUrl(current_route_1);
@Url.RouteUrl(current_route_2);
Url.Action reutilizará los parámetros de solicitud actuales, si no los configura explícitamente. Es por diseño en el algoritmo de alineación de URL salientes. Al buscar los parámetros de datos de ruta en un proceso de generación de url, los parámetros se toman de:
1) valores proporcionados explícitamente
2) valores de la solicitud actual
3) valores predeterminados
En el orden que especifiqué arriba.
El algoritmo de coincidencia de salida para las rutas es complicado, por lo que es una buena práctica establecer explícitamente todos los parámetros para la solicitud, como lo hizo en su ejemplo