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.
我正在研究的网站有一些相当复杂的路由结构,我们在使用路由引擎来构建URL时遇到了一些困难,就像我们需要构建它们一样。
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.
我们有一个搜索结果页面,它使用基于RegEx的模式匹配将几个变量组合成一个路径段(即“www.host.com/{structuralParameters}”可以是:“www.host.com/variableA-variableB- variableC“ - 其中变量A到C都是可选的)。经过一番工作,这对我们很有用。
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!
我们遇到的问题解决了ActionLink方法的烦人特征:如果指向相同的控制器/操作,它将保留现有的路由值,无论您是否需要它们。我们更喜欢控制链接的外观,在某些情况下,不能保留现有参数。一个例子是我们网站的主导航导向没有设置参数的搜索结果页面 - 如果您愿意,可以使用默认搜索页面。我说这是一个烦人的功能,因为它是一个罕见的ASP.Net MVC框架实例,似乎在没有明显扩展点的情况下决定实现 - 我们宁愿不在我们的母版页中创建自定义ActionLink代码来编写简单的导航链接!
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.
我看到有人说你需要明确地将这些参数设置为空字符串,但是当我们尝试这个时它只是将参数从路由值更改为查询字符串参数。对我来说似乎不应该要求我们明确地将我们没有显式传递的值作为参数传递给ActionLink方法,但如果这是我们唯一的选项,我们将使用它。但是目前如果它在查询字符串中显示,那么将参数直接放入路径对我们来说是无用的。
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.
我知道我们的路由结构加剧了这个问题 - 如果我们使用更简单的方法(即www.host.com/variableA/variableB/variableC),我们可能不会有任何问题,但我们的URL结构不可协商 - 它是旨在满足与可用性,SEO和链接/内容共享相关的非常具体的需求。
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?
我们如何使用Html.ActionLink生成页面链接,而不会回退到当前路径数据(或者,如果可能,需要明确排除路径段),即使这些链接导致相同的操作方法?
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:
编辑:根据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" }
);
3 个解决方案
#1
20
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.
在调用Html.ActionLink或Html.RouteLink(或任何URL生成方法)时将路由值设置为null或空字符串将清除“环境”路由值。
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".
例如,使用标准的MVC控制器/ action / id路由,假设您在“Home / Index / 123”上。如果你调用Html.RouteLink(new {id = 456}),那么MVC会注意到controller =“Home”和action =“Index”的“环境”路由值。它还会注意到id =“123”的环境路由值,但是会被显式的“456”覆盖。这将导致生成的URL为“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).
参数的排序也很重要。例如,假设您调用了Html.RouteLink(new {action =“About”})。 “关于”操作将覆盖当前的“索引”操作,“id”参数将完全清除!但是,为什么,你问?因为一旦您使参数段无效,那么之后的所有参数段都将失效。在这种情况下,“action”被新的显式值无效,因此“id”(在它之后,并且没有显式值)也会失效。因此,生成的URL将只是“Home / About”(没有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".
在同样的情况下,如果你调用Html.RouteLink(new {action =“”}),那么生成的URL将只是“Home”,因为你使用空字符串使“action”无效,然后导致“id”到也会失效,因为它是在无效的“行动”之后发生的。
#2
4
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...
我编写了一个名为RouteWithExclusions的自定义Route类,它能够定义在生成URL时应排除/删除的路由值名称。问题是当路由通过路由表落下并且后续路由没有相同的路由值名称时......
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.
整个问题在我的博客文章中详细说明并且也提供了所有代码。检查一下,它可以帮助您解决此路由问题。我还写了两个额外的MapRoute扩展方法,它们带有一个额外的参数。
#3
1
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.
在href属性中替换您需要的任何内容。
#1
20
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.
在调用Html.ActionLink或Html.RouteLink(或任何URL生成方法)时将路由值设置为null或空字符串将清除“环境”路由值。
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".
例如,使用标准的MVC控制器/ action / id路由,假设您在“Home / Index / 123”上。如果你调用Html.RouteLink(new {id = 456}),那么MVC会注意到controller =“Home”和action =“Index”的“环境”路由值。它还会注意到id =“123”的环境路由值,但是会被显式的“456”覆盖。这将导致生成的URL为“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).
参数的排序也很重要。例如,假设您调用了Html.RouteLink(new {action =“About”})。 “关于”操作将覆盖当前的“索引”操作,“id”参数将完全清除!但是,为什么,你问?因为一旦您使参数段无效,那么之后的所有参数段都将失效。在这种情况下,“action”被新的显式值无效,因此“id”(在它之后,并且没有显式值)也会失效。因此,生成的URL将只是“Home / About”(没有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".
在同样的情况下,如果你调用Html.RouteLink(new {action =“”}),那么生成的URL将只是“Home”,因为你使用空字符串使“action”无效,然后导致“id”到也会失效,因为它是在无效的“行动”之后发生的。
#2
4
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...
我编写了一个名为RouteWithExclusions的自定义Route类,它能够定义在生成URL时应排除/删除的路由值名称。问题是当路由通过路由表落下并且后续路由没有相同的路由值名称时......
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.
整个问题在我的博客文章中详细说明并且也提供了所有代码。检查一下,它可以帮助您解决此路由问题。我还写了两个额外的MapRoute扩展方法,它们带有一个额外的参数。
#3
1
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.
在href属性中替换您需要的任何内容。