如何停止 ASP.Net MVC Html.ActionLink 使用现有的路由值?

13
我所工作的网站有一些相当复杂的路由结构,我们在使用路由引擎构建URL时遇到了一些困难。我们有一个搜索结果页面,它使用基于正则表达式的模式匹配将多个变量分组到单个路由段中(例如,“www.host.com/{structuralParameters}”可以是以下内容:“www.host.com/variableA-variableB-variableC” - 其中变量A到C都是可选的)。在一些努力后,这对我们运行良好。
我们遇到的问题与ActionLink方法的一个令人恼火的特性有关:如果指向相同的控制器/操作,它将保留现有的路由值,无论您是否想要它们。我们更喜欢控制我们的链接外观,并且在某些情况下,不能保留现有的参数。一个例子是,我们网站的主导航指向没有设置参数的搜索结果页面 - 一个默认的搜索页面。我说这是一个令人恼火的特性,因为这是ASP.Net MVC框架似乎在没有明显扩展点的情况下支配实现的罕见实例 - 我们不想在我们的主页上编写自定义ActionLink代码来创建一个简单的导航链接!
我看到有些人说,您需要显式地将这些参数设置为空字符串,但是当我们尝试这样做时,它只会将参数从路由值更改为查询字符串参数。我认为我们不应该被要求显式排除我们未明确传递为参数的值,但是如果这是我们唯一的选择,我们将使用它。但是目前,如果它在查询字符串中显示,那么对于我们来说就像将参数直接放入路由一样毫无用处。
我知道我们的路由结构加剧了这个问题 - 如果我们使用更简单的方法(例如www.host.com/variableA/variableB/variableC),我们可能不会有任何问题,但我们的URL结构是不可谈判的 - 它被设计来满足与可用性、SEO和链接/内容共享相关的非常具体的需求。
如何使用Html.ActionLink生成到页面的链接,而不陷入当前路由数据(或需要显式排除路由段)的陷阱,即使这些链接指向相同的操作方法?
如果我们需要显式排除路由段,如何防止该方法将路由呈现为查询字符串参数?
这个看似小小的问题给我们带来了惊人的困扰,我将感激任何帮助解决它的方法。
编辑:根据LukLed的要求,以下是一个ActionLink调用示例:
// I've made it generic, but this should call the Search action of the 
// ItemController, the text and title attribute should say "Link Text" but there
// should be no parameters - or maybe just the defaults, depending on the route.
// 
// Assume that this can be called from *any* page but should not be influenced by
// the current route - some routes will be called from other sections with the same
// structure/parameters.
Html.ActionLink( 
    "Link Text",
    "Search", 
    "Item", 
    new { }, 
    new { title = "Link Text" } 
);

你能举个调用ActionLink函数及其结果的例子吗?虽然你写了很多,但我觉得例子会更好地解释它。 - LukLed
已添加示例ActionLink。正如您所见,我在匿名对象中未提供任何参数(我们还尝试将其明确设置为空字符串)。 - Zac Seth
3个回答

21
在调用Html.ActionLinkHtml.RouteLink(或任何URL生成方法)时将路由值设置为null或空字符串会清除“环境”路由值。例如,对于标准MVC控制器/操作/ id路由,假设您在“Home/Index/123”上。如果您调用Html.RouteLink(new { id = 456 }),那么MVC将注意到controller =“Home”action =“Index” 的“环境”路由值。它还将注意到环境路由值id =“123”,但是这将被显式的“456”覆盖。这将导致生成的URL为“Home / Index / 456”。
参数的排序也很重要。例如,假设您调用Html.RouteLink(new { action =“About”})。 “About”操作将覆盖当前的“Index”操作,并且"id"参数将完全被清除!但是为什么呢?因为一旦使参数段无效,则在其后的所有参数段都将无效。在此情况下,“action”被新的显式值使其无效,因此在其后出现的“id”也被使无效,因为它没有显式值。因此,生成的URL将仅为“Home / About”(不带ID)。
在相同的场景中,如果您调用Html.RouteLink(new { action =“”}),则生成的URL将仅为“Home”,因为您用空字符串使“action”无效,然后导致“id”也被无效化,因为它在无效的“action”之后出现。

我无法重现您在帖子中提到的行为。我有Html.ActionLink(“abc”,“actionA”,new {docid = 4,id = 5})并且在此页面上,当我呈现链接Html.ActionLink(“xyz”,“actionB”,new {id = 90}),根据您的解释,它应该清除docid,因为我更改了操作参数,但它没有清除docid并在链接生成中使用它。我在这个环境值问题上遇到了很多麻烦。使用.NET 4与mvc2 - Muhammad Adeel Zahid
@Muhammad,参数清除的问题取决于生成所选路由。如果在该路由中,{docid}参数出现在其他已更改的参数之前,则环境值将保持不变。如果您可以分享您的代码,我可以进行调查。我建议在StackOverflow上打开一个新问题,并从这里链接到它(确保在评论中提到@Eilon,以便通知我!)。 - Eilon
是的,您所说的行为是正确的。只是我有点错了。我已经在这里发布了我的代码和问题: https://dev59.com/qE_Ta4cB1Zd3GeqPDsA1,请看一下。 - Muhammad Adeel Zahid
+1 我想不出更好的默认路由和参数无效的解释。 - Ken D
这个答案在6年后仍然相关,但是第一个重载已经改变,需要2个参数,第一个参数是链接文本。这将把最小答案更改为Html.RouteLink(" ", new { action = "" })。 - MeanGreen

4

问题的根源解决方案

看起来最佳解决方案(不像是一个变通之策)是解决问题的根源,而这个根源在于路由。

我编写了一个名为RouteWithExclusions的自定义Route类,能够定义应在生成URL时排除/删除的路由值名称。问题是当路由通过路由表并且随后的路由没有相同的路由值名称时...

整个问题在我的博客文章中详细解释,并提供了所有代码。请查看它,它可能会帮助您解决这个路由问题。我还编写了两个额外的MapRoute扩展方法,它们带有一个附加参数。


0
如果您想完全控制链接,只需自己构建链接即可:
<a href="~/variableA/variableB/<%= Html.Encode(Model.Target) %>">Click Here</a>

href 属性中替换任何你需要的内容。


1
是的,这是一个选项 - 而且在节省时间方面值得考虑。我对这种方法的担忧是,将来我们可能需要更改路由,最好在路由字典中进行而不是每个单独的视图中进行 - 即使只有少数视图受到影响。这样做会留下更多的机会让人为错误导致错误...无论如何,在这种情况下,这可能是最好的选择。 - Zac Seth
听起来你想让它只跟随部分路线。为了做到这一点,你需要筛选路线字典并从中构建一个URL。 - Robert Harvey
就记录而言,您可能不需要在URL中使用所有这些斜杠来获得良好的SEO。请查看此页面浏览器中的URL。StackOverflow SEO是最好的。 - Robert Harvey
是的,我开始觉得我需要按照你建议的路由字典的方式做些什么。可能会封装在自定义ActionLink扩展方法中。StackOverflow在优化其网站方面做得非常出色 - 否则为什么他们总能在我的搜索结果中排名第一呢?;-) 然而,他们的网站内容结构比我们清晰得多 - 而我们没有改变这一点的立场。据我所知,我们的URL策略是正确的(我们最近在这个领域投入了很多工作),但它确实使事情变得复杂。 - Zac Seth

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接