2009-07-18 120 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 

我不確定這是否可以接受的解決方案,但它是一種替代方案,不是嗎?