Asp.net-Mvc-Routing

如何防止 Url.RouteUrl(…) 從目前請求繼承路由值

  • July 18, 2009

假設您有一個在購物車中顯示產品的操作方法

// 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。

在這種情況下,一旦您弄清楚了,您可以通過多種方式輕鬆修復它,但在其他情況下可能會導致一些危險行為。這可能是設計使然,但它絕對是可怕的。

我的解決方案是這樣的:

一個 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”創建一個新的。這意味著沒有任何東西可以繼承(甚至是空值)。

引用自:https://stackoverflow.com/questions/1148443