2009-07-18 44 views
30

继承路由值比方说你有一个动作方法,在购物车中,以显示产品如何防止Url.RouteUrl(...)从当前请求

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

     // get all products for the gender 
} 

在其他地方,在报头是

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

testimonials-routeglobal.ascx通过下面的第一个路线定义:您正在使用Url.RouteUrl创建HREF链接到该网站上的其他网页的每一页上显示。 注意,以RouteUrl上面的电话不提供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)" } 
); 

如果有人访问/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)方法。当我们使用testimonials-route创建URL时,对Url.RouteUrl()的调用实际上继承了gender的THIS空值。即使我们在'testimionials-route中指定了gender的默认值,它仍会使用该空值,导致路由失败,并且RouteUrl返回null。 [注意:路由失败,因为我们有一个约束,而null不适合]

它实际上变得更可怕 - 在'控制器'和'行动'可以继承一样的方法。即使使用具有默认控制器的明确路由名称来呼叫RouteUrl(...),也可能导致URL生成为完全错误的控制器。

在这种情况下,一旦你理解了它,你可以通过多种方式很容易地解决它,但它可以在其他情况下会造成一些危险的行为。这可能是通过设计,但它绝对可怕。

+0

在原始问题后的一年半后添加赏金,因为(a)我想知道框架现在是否为我做了这件事,(b)我很好奇为什么这只有两个upvotes。认为这是一个普遍的问题,所以想知道如果我做错了什么! – 2011-01-01 03:06:48

+0

这是踢我的短靴,因为{域}标签缺乏价值,但系统应该自动提供。一旦我改变了这个,它就起作用了。 – 2011-03-19 16:24:11

+0

为什么不直接调用RenderUrl就好了:`”` - 因此,没有任何东西会被覆盖。 – Gerwald 2012-03-14 12:48:14

回答

26

我的解决办法是这样的:

的HtmlExtension helper方法:

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'的新的。这意味着没有什么可以继承(甚至是空值)。

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而不是网址.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 

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