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

发布于 2024-08-12 19:02:05 字数 1610 浏览 8 评论 0原文

我正在开发的网站有一些相当复杂的路由结构,我们在使用路由引擎按照我们需要的方式构建 URL 时遇到了一些困难。

我们有一个搜索结果页面,它使用基于正则表达式的模式匹配将多个变量分组到单个路线段中(即“www.host.com/{structuralParameters}”可以是以下内容:“www.host.com/variableA-variableB-变量C” - 其中变量A到C都是可选的)。经过一番工作后,这对我们来说效果很好。

我们遇到的问题解决了 ActionLink 方法的一个恼人的功能:如果您指向相同的控制器/操作,无论您是否需要,它都会保留现有的路由值。我们更愿意控制链接的外观,并且在某些情况下,无法保留现有参数。一个例子是我们网站的主导航指向没有设置参数的搜索结果页面 - 如果您愿意,可以选择默认搜索页面。我说这是一个烦人的功能,因为它是 ASP.Net MVC 框架的罕见实例,看似规定了实现,但没有明显的扩展点 - 我们不希望创建自定义 ActionLink 代码来在我们的母版页中编写简单的导航链接!

我看到有人说您需要显式地将这些参数设置为空字符串,但是当我们尝试这样做时,它只是将参数从路由值更改为查询字符串参数。在我看来,我们应该被要求显式排除我们没有显式作为参数传递给 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" } 
);

The website I'm working on has some fairly complicated routing structures and we're experiencing some difficulties working with the routing engine to build URLs the way we need them to be built.

We have a search results page that uses RegEx based pattern matching to group several variables into a single route segment (i.e. "www.host.com/{structuralParameters}" can be the following: "www.host.com/variableA-variableB-variableC" - where variables A through C are all optional). This is working for us fine after a bit of work.

The problem we are experiencing resolves around an annoying feature of the ActionLink method: if you point to the same controller/action it will retain the existing route values whether you want them or not. We prefer to have control over what our links look like and, in some cases, cannot have the existing parameters retained. An example would be where our site's main navigation leads to a search results page with no parameters set - a default search page, if you like. I say this is an annoying feature because it is a rare instance of the ASP.Net MVC Framework seemingly dictating implementation without an obvious extension point - we would prefer not to create custom ActionLink code to write a simple navigation link in our master page!

I've seen some say that you need to explicitly set such parameters to be empty strings but when we try this it just changes the parameters from route values into query string parameters. It doesn't seem right to me that we should be required to explicitly exclude values we aren't explicitly passing as parameters to the ActionLink method but if this is our only option we will use it. However at present if it is displaying in the query string then it is as useless to us as putting the parameters directly into the route.

I'm aware that our routing structure exasperates this problem - we probably wouldn't have any issue if we used a simpler approach (i.e. www.host.com/variableA/variableB/variableC) but our URL structure is not negotiable - it was designed to meet very specific needs relating to usability, SEO, and link/content sharing.

How can we use Html.ActionLink to generate links to pages without falling back on the current route data (or, if possible, needing to explicitly excluding route segments) even if those links lead to the same action methods?

If we do need to explicitly exclude route segments, how can we prevent the method from rendering the routes as query string parameters?

This seemingly small problem is causing us a surprising amount of grief and I will be thankful for any help in resolving it.

EDIT: As requested by LukLed, here's a sample ActionLink call:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

蓝眸 2024-08-19 19:02:05

当调用 Html.ActionLinkHtml.RouteLink (或任何 URL 生成方法)时,将路由值设置为 null 或空字符串将清除“环境”路由值。

例如,使用标准 MVC 控制器/操作/id 路由,假设您位于“Home/Index/123”。如果您调用 Html.RouteLink(new { id = 456 }),那么 MVC 将注意到 controller="Home"action= 的“环境”路由值“索引”。它还会注意到 id="123" 的环境路由值,但该值将被显式“456”覆盖。这将导致生成的 URL 为“Home/Index/456”。

参数的顺序也很重要。例如,假设您调用了 Html.RouteLink(new { action = "About" })。 “关于”操作将覆盖当前的“索引”操作,并且“id”参数将被完全清除!但你问为什么?因为一旦使一个参数段无效,那么该参数段之后的所有参数段都将失效。在这种情况下,“action”因新的显式值而无效,因此紧随其后并且没有显式值的“id”也会变得无效。因此,生成的 URL 将只是“Home/About”(没有 ID)。

在同一场景中,如果您调用 Html.RouteLink(new { action = "" }),那么生成的 URL 将只是“Home”,因为您使用空字符串使“action”无效,然后这也导致“id”无效,因为它出现在无效的“action”之后。

Setting route values to be null or empty string when calling Html.ActionLink or Html.RouteLink (or any URL generation method) will clear out the "ambient" route values.

For example, with the standard MVC controller/action/id route suppose you're on "Home/Index/123". If you call Html.RouteLink(new { id = 456 }) then MVC will notice the "ambient" route values of controller="Home" and action="Index". It will also notice the ambient route value of id="123" but that will get overwritten by the explicit "456". This will cause the generated URL to be "Home/Index/456".

The ordering of the parameters matters as well. For example, say you called Html.RouteLink(new { action = "About" }). The "About" action would overwrite the current "Index" action, and the "id" parameter would get cleared out entirely! But why, you ask? Because once you invalidate a parameter segment then all parameter segments after it will get invalidated. In this case, "action" was invalidated by a new explicit value so the "id", which comes after it, and has no explicit value, also gets invalidated. Thus, the generated URL would be just "Home/About" (without an ID).

In this same scenario if you called Html.RouteLink(new { action = "" }) then the generated URL would be just "Home" because you invalidated the "action" with an empty string, and then that caused the "id" to be invalidated as well because it came after the invalidated "action".

甜`诱少女 2024-08-19 19:02:05

问题根源的解决方案

似乎最佳解决方案(听起来不像解决方法)是解决问题根源的解决方案,即路由。

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

整个问题在 我的博客文章 也在那里提供了所有代码。看看吧,它可能会帮助你解决这个路由问题。我还编写了两个带有附加参数的附加 MapRoute 扩展方法。

Solution at the root of the problem

It seems that the optimal solution (that doesn't smell like a workaround) is the one that solves the problem where it has roots and that's in routing.

I've written a custom Route class called RouteWithExclusions that is able to define route value names that should be excluded/removed when generating URLs. The problem is when routing falls through routes table and subsequent routes don't have the same route value names...

The whole problem is detailed and explained in my blog post and all the code is provided there as well. Check it out, it may help you solve this routing problem. I've also written two additional MapRoute extension methods that take an additional parameter.

对你再特殊 2024-08-19 19:02:05

如果您想完全控制链接,只需自己构建链接:

<a href="~/variableA/variableB/<%= Html.Encode(Model.Target) %>">Click Here</a>

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

If you want total control of the link, just build the link yourself:

<a href="~/variableA/variableB/<%= Html.Encode(Model.Target) %>">Click Here</a>

Substitute whatever you need inside the href attribute.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文