如何防止Url.RouteUrl(...)从当前请求继承路由值

Sim*_*ver 31 asp.net-mvc-routing

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

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

      // get all products for the gender
 }
Run Code Online (Sandbox Code Playgroud)

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

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

这由下面的第一条路线testimonials-route定义global.ascx.请注意,上面的调用RouteUrl不提供a gender,但是路由定义为默认的"中性",所以我们期望调用Testimonials.Index("中性").

 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)" }
 );
Run Code Online (Sandbox Code Playgroud)

如果有人访问该页面/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时,Url.RouteUrl()实际上会继承THIS null值的调用.即使我们在'中指定了默认值,它仍然使用此空值,这会导致路由失败并返回null.[注意:路线失败,因为我们有一个约束(男人|女人|中立),而null不适合]gendertestimonials-routegender'testimionials-routeRouteUrl

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

在这种情况下,一旦你弄明白了,你可以通过多种方式轻松解决它,但在其他情况下可能会导致一些危险的行为.这可能是设计上的,但它绝对是可怕的.

Sim*_*ver 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);
        }
    }
Run Code Online (Sandbox Code Playgroud)

我现在可以这样做:

Url.RouteUrl('testimonials-route', new { }, false)
Run Code Online (Sandbox Code Playgroud)

并且确切地知道无论上下文如何,它总是会以相同的方式运行.

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