未提供路由名称时使用 RouteLink 生成 url 的方法是什么?

What is the method for generating urls using RouteLink when a route name is not supplied?

@Html.RouteLink 与路由名称一起使用只是指示路由引擎使用该名称的路由。这很容易理解,而且显然也是任何撰写博客条目或文档的人试图解释 RouteLink 的唯一方式。

我很欣赏这是首选方法,我也一直在 RouteLink 中使用路线名称,但我想知道当我们不这样做时它是如何工作的,但我找不到任何关于它的真正有用的信息。所以问题的方法是:

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

为了与 MSDN 上所有有趣的东西保持一致,it's not explained at all

Haacked.com has examples of using RouteLink 这种方式:

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})

当我读到它时,我认为这是一个错字,两者实际上都将绑定到 "Default",但实际上并没有。带有文本 "Test" 的 link 生成为 https://localhost:44301/code/p/Index/123.

似乎 "wrong" 因为对我来说默认值通常在提供 none 时使用,但在这里它们在生成期间用作查找值。它既奇怪又松散,我不记得曾经这样做过,也想不出我会这样做的原因。

如果我这样做:

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

它不起作用,但如果我这样做:

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

它仍然如此,似乎只有控制器值很重要,但就生成的 url 而言,它完全未被使用。

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

在 Haacked.com,菲尔说:

There’s even more details I’ve glossed over having to do with how a route’s default values figure into URL generation. That’s a topic for another time, but it explains why you don’t run into this problem with routes to controller actions which have an URL without parameters.

但他似乎再也没有回到那个话题。我已经查看了源代码,但我已经进行了 30 次深入调用,并且徘徊在无处可去的抽象 类 中,我现在无法从符号服务器上逐步执行它。

那么是不是"controller names become route names, in the absence of actual route names during url generation"那么简单呢?如果是这样,他们为什么这样做/允许这样做?

如果不传递路由名称,@Html.ActionLink()@Html.RouteLink 看起来会做同样的事情。

看看下面的方法(在RouteCollectionExtensions.cs中找到)。 name这里的参数是路由名称

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);
}

您可以看到它根据路由名称是否为空采取不同的操作。

为了回答您的问题,如果路由名称不是通过。

更新

我不确定控制器名称如何成为路由名称,因为在下面的方法调用中,您可以看到动作名称和控制器名称都传递了空值:

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);
}

我四处寻找并解释专业ASP.NET MVC 4 作者:Jon Galloway、Phil Haack、Brad Wilson、K. Scott Allen 在我的问题中概述的场景中,url 中不存在的默认值成为必须提供值的键控开关匹配 RouteLink 中的默认值,以便 link 被视为 url 生成的匹配项。

所以如果你有这样的路线:

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

然后为了考虑它,您必须在路由link 中提供控制器="section" 值。 {action} 无关紧要,因为它是 url 的一部分,而 {controller} 本身并不重要。它是任何 {parameter},默认值不在 url.

如此给出

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

我们需要在我的 RouteLink

中提供水果="bananas"
@Html.RouteLink("Test", new {fruit="bananas", action="IndexA", id=123})

另请注意,它不是 基于顺序。所以并不是 url 中不存在的第一个 {parameter} 成为关键,而是 url 中不存在的所有 {parameter} 成为关键所以实际上你可以有一个复合键按照:

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

您需要如下定义的 RouteLink 才能匹配:

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

如果你Google

a detailed look at url generation

您将获得 Google 本书 link 解释这一点的页面。我将此称为 "keyed switch",因为根据流程图,匹配键会为给定路线打开和关闭路线考虑。

我仍然想不出一个很好的理由来说明为什么我会通过命名路由执行此操作以及为什么它受到特别支持。