El uso de @Html.RouteLink con un nombre de ruta simplemente indica al motor de enrutamiento que use la ruta con ese nombre. Esto es fácil de entender y, aparentemente, también es la única forma en que cualquiera que escriba una entrada de blog o la documentación intente explicar RouteLink.

Aprecio que este es el método preferido y yo también siempre he usado un nombre de ruta con RouteLink, pero quiero saber cómo funciona cuando no lo hacemos y no puedo encontrar ninguna información realmente buena al respecto. Entonces el método es la pregunta:

public static MvcHtmlString RouteLink(
    this HtmlHelper htmlHelper,
    string linkText,
    RouteValueDictionary routeValues
)

Y de acuerdo con todas las cosas interesantes en MSDN, es no explicado en absoluto.

Haacked.com tiene ejemplos de uso de RouteLink de esta manera:

routes.MapRoute(
    name: "Test",
    url: "code/p/{action}/{id}",
    defaults: new { controller = "Section", action = "Index", id = "" }
);

routes.MapRoute(
    name: "Default",
    url: "{controller}/{action}/{id}",
    defaults: new { controller = "Home", action = "Index", id = "" }
);

@Html.RouteLink("Test", new {controller="section", action="Index", id=123})

@Html.RouteLink("Default", new {controller="Home", action="Index", id=123})

Cuando leí eso, pensé que era un error tipográfico que ambos se vincularían a "Predeterminado", pero no, realmente funciona. El enlace con el texto "Prueba" se genera como https://localhost:44301/code/p/Index/123.

Me pareció "incorrecto" porque para mí los valores predeterminados se utilizan normalmente cuando no se proporciona ninguno, pero aquí se utilizan como valores de búsqueda durante la generación. Es extraño y suelto y no recuerdo haberlo hecho nunca de esta manera ni puedo pensar en una razón por la que alguna vez lo haría de esta manera.

Si hago esto:

 @Html.RouteLink("Test", new {controller="sectionA", action="Index", id=123})

No funciona pero si hago esto:

 @Html.RouteLink("Test", new {controller="section", action="IndexA", id=123})

Todavía lo hace, por lo que parece que solo el valor del controlador es significativo y, sin embargo, está completamente sin usar en lo que respecta a la URL generada.

https://localhost:44301/code/p/Index/123

En Haacked.com, Phil dice:

Hay incluso más detalles que he pasado por alto sobre la forma en que los valores predeterminados de una ruta figuran en la generación de URL. Ese es un tema para otro momento, pero explica por qué no se encuentra con este problema con las rutas a las acciones del controlador que tienen una URL sin parámetros.

Pero parece que nunca volvió a ese tema. He mirado la fuente, pero tengo 30 llamadas de profundidad y deambulando por clases abstractas que no llevan a ninguna parte y no estoy en condiciones de pasar de un servidor de símbolos en este momento.

Entonces, ¿es tan simple como "los nombres de los controladores se convierten en nombres de rutas, en ausencia de nombres de rutas reales durante la generación de URL"? Y si es así, ¿por qué hicieron / permitieron esto?

3
rism 10 feb. 2015 a las 13:47

2 respuestas

La mejor respuesta

Estoy buscando y parafraseando ASP.NET MVC 4 profesional Por Jon Galloway, Phil Haack, Brad Wilson, K. Scott Allen en el escenario descrito en mi pregunta, los valores predeterminados que no están presentes en la URL se convierten en una especie de interruptor con llave que debe proporcionarse con valores que coincidan con los valores predeterminados en el RouteLink para que ese enlace se considere una coincidencia para la generación de URL.

Entonces, si tienes una ruta como:

routes.MapRoute(
    name: "Test",
    url: "code/p/{action}/{id}",
    defaults: new { controller = "Section", action = "Index", id = "" }
);

Luego, para que se considere, debe proporcionar un valor controller = "section" en el enlace de ruta. {action} no importa, ya que es parte de la URL y {controller} en sí no es significativo. Es cualquier {parameter} con un valor predeterminado que no está en la URL.

Así dado

routes.MapRoute(
    name: "Test",
    url: "code/p/{action}/{id}",
    defaults: new { fruit = "bananas", action = "Index", id = "" }
);

Necesitaríamos proporcionar una fruta = "plátanos" en mi RouteLink

@Html.RouteLink("Test", new {fruit="bananas", action="IndexA", id=123})

También tenga en cuenta que no se basa en el pedido. Entonces no es que el primer {parameter} que no está presente en la URL se convierta en la clave, todo {parameter} que no está presente en la URL se convierte en la clave, por lo que, en efecto, podría tener una clave compuesta según:

routes.MapRoute(
    name: "Test",
    url: "code/p/{action}/{id}",
    defaults: new { fruit = "bananas", insect="honeybee", action = "Index", id = "" }
);

Necesitaría un RouteLink definido como se muestra a continuación para una coincidencia:

@Html.RouteLink("Test", new {fruit="bananas", insect="honeybee", action="IndexA", id=123})

Si buscas en Google

una mirada detallada a la generación de URL

Obtendrá el enlace de libros de Google para las páginas que explican esto. Me refiero a esto como un "interruptor con llave" porque, según el diagrama de flujo, una llave coincidente activa y desactiva la consideración de ruta para una ruta determinada.

Todavía no puedo pensar en una buena razón de por qué alguna vez haría esto en una ruta con nombre y, por lo tanto, es específicamente compatible.

enter image description here

0
rism 10 feb. 2015 a las 21:55

Parece que @Html.ActionLink() y @Html.RouteLink hacen lo mismo si no se pasa el nombre de la ruta.

Eche un vistazo al siguiente método (que se encuentra en RouteCollectionExtensions.cs). El parámetro name es el nombre de la ruta aquí.

internal static VirtualPathData GetVirtualPathForArea(this RouteCollection routes, RequestContext requestContext, string name, RouteValueDictionary values, out bool usingAreas)
{
  if (routes == null)
    throw new ArgumentNullException("routes");
  if (!string.IsNullOrEmpty(name))
  {
    usingAreas = false;
    return routes.GetVirtualPath(requestContext, name, values);
  }
  string areaName = (string) null;
  if (values != null)
  {
    object obj;
    if (values.TryGetValue("area", out obj))
      areaName = obj as string;
    else if (requestContext != null)
      areaName = AreaHelpers.GetAreaName(requestContext.RouteData);
  }
  RouteValueDictionary values1 = values;
  RouteCollection routeCollection = RouteCollectionExtensions.FilterRouteCollectionByArea(routes, areaName, out usingAreas);
  if (usingAreas)
  {
    values1 = new RouteValueDictionary((IDictionary<string, object>) values);
    values1.Remove("area");
  }
  return routeCollection.GetVirtualPath(requestContext, values1);
}

Puede ver que toma diferentes acciones en función de si el nombre de la ruta es nulo o no.

Para responder a su pregunta, el comportamiento de @Html.ActionLink() y @Html.RouteLink() será el mismo (seleccionarán la misma ruta según la configuración) si no se pasa el nombre de la ruta.

Actualizar

No estoy seguro de cómo el nombre del controlador puede convertirse en el nombre de la ruta porque en la siguiente llamada al método puede ver que los nulos se pasan tanto para el nombre de la acción como para el nombre del controlador:

public static string GenerateRouteLink(RequestContext requestContext, RouteCollection routeCollection, string linkText, string routeName, string protocol, string hostName, string fragment, RouteValueDictionary routeValues, IDictionary<string, object> htmlAttributes)
{
  return HtmlHelper.GenerateLinkInternal(requestContext, routeCollection, linkText, routeName, (string) null, (string) null, protocol, hostName, fragment, routeValues, htmlAttributes, false);
}
0
Imran Rashid 10 feb. 2015 a las 11:38