31

假设您有一个在购物车中显示产品的操作方法

 // ProductsController.cs
 public ActionMethod Index(string gender) {

      // get all products for the gender
 }

在其他地方,在您Url.RouteUrl用来创建指向站点上其他页面的 HREF 链接的每个页面上显示的标头中:

 <a href="<%= Url.RouteUrl("testimonials-route", new { }) %>" All Testimonials </a>

testimonials-routeglobal.ascx由下面的第一条路线定义的。请注意,上面的调用RouteUrl不提供 a gender,但路由定义为默认值 'neutral',因此我们希望调用 Testimonials.Index("neutral")。

 routes.MapRoute(
  "testimonials-route",
  "testimonials/{gender}",
  new { controller = "Testimonials", action = "Index", gender = "neutral" },
  new { gender = "(men|women|neutral)" }
 );

routes.MapRoute(
  "products-route",
  "products/{gender}",
  new { controller = "Products", action = "Index", gender = (string)null },
  new { gender = "(men|women|neutral)" }
 );

如果有人访问该页面/products/women,我们会得到一个 HREF。/testimonials/women 如果有人访问该页面/products,那么我们会得到一个空的 HREF(对 RouteUrl 的调用返回 null)。

但这没有意义不是吗?如果我们不为它提供路由值,testimonials-route应该默认为我们?'neutral'

事实证明,Url.RouteUrl(routeName, routeValues)辅助扩展将首先在其routeValues参数中查找gender路由值,如果在该字典中找不到它,它将查看我们所在的当前 URL(请记住,Url 是 UrlHelper 对象它具有可用的当前请求的上下文)。

如果我们在男士产品页面上,这可能会给我们一个男士推荐的链接,但如果我们没有在RouteUrl调用中传递值并明确指定“中性”,这可能不是我们想要的文件中的默认值global.asax.cs

在我们访问的情况下,/products/我们触发了'products-route'路由并Products(null)调用了该方法。当Url.RouteUrl()我们gender使用testimonials-route. 即使我们为genderin 'testimionials-route' 指定了默认值,它仍然使用这个 null 值,这会导致路由失败并RouteUrl返回 null。[注意:路由失败是因为我们对 (men|women|neutral) 有限制,而 null 不适合]

它实际上变得更可怕 - 因为“控制器”和“动作”可以以相同的方式继承。即使使用具有默认控制器的显式路由名称调用 RouteUrl(...),这也可能导致生成完全错误的控制器的 URL。

在这种情况下,一旦您弄清楚了,您可以通过多种方式轻松修复它,但在其他情况下可能会导致一些危险行为。这可能是设计使然,但它绝对是可怕的。

4

2 回答 2

26

我的解决方案是这样的:

一个 HtmlExtension 辅助方法:

    public static string RouteUrl(this UrlHelper urlHelper, string routeName, object routeValues, bool inheritRouteParams)
    {
        if (inheritRouteParams)
        {
            // call standard method
            return urlHelper.RouteUrl(routeName, routeValues);
        }
        else
        {
            // replace urlhelper with a new one that has no inherited route data
            urlHelper = new UrlHelper(new RequestContext(urlHelper.RequestContext.HttpContext, new RouteData()));
            return urlHelper.RouteUrl(routeName, routeValues);
        }
    }

我现在可以这样做:

Url.RouteUrl('testimonials-route', new { }, false)

并确定无论上下文如何,它都会始终以相同的方式运行。

它的工作方式是使用现有的UrlHelper并使用空白的“RouteData”创建一个新的。这意味着没有任何东西可以继承(甚至是空值)。

于 2009-07-18T20:03:24.120 回答
2

也许我在这里遗漏了一些东西,但为什么不这样设置:

在您的全局 asax 中,创建两条路线:

routes.MapRoute(
    "testimonial-mf",
    "Testimonials/{gender}",
    new { controller = "Testimonials", action = "Index" }
);

routes.MapRoute(
    "testimonial-neutral",
    "Testimonials/Neutral",
    new { controller = "Testimonials", action = "Index", gender="Neutral" }
);

然后,使用 Url.Action 代替 Url.RouteUrl:

<%= Url.Action("Testimonials", "Index") %>
<%= Url.Action("Testimonials", "Index", new { gender = "Male" }) %>
<%= Url.Action("Testimonials", "Index", new { gender = "Female" }) %>

其中,在我的机器上解析为以下网址:

/Testimonials/Neutral 
/Testimonials/Male 
/Testimonials/Female

我不确定这是否是一个可接受的解决方案,但它是一个替代方案,不是吗?

于 2011-01-08T01:55:49.590 回答