2016-05-31 24 views
0

我有一個運行在.NET 4.6.1上的ASP.NET MVC 5 Web應用程序。UrlHelper.RouteUrl(routeName,RouteValueDictionary)返回null

我有一個區域,在我所謂的「富」應用程序,在我區註冊時,我添加了一個名爲路線,像這樣:

RegisterArea(AreaRegistrationContext context) { 

    context.MapRoute("Foo_Bar", "{tenantName}/foo/{fooId}/{fooRevision}", new { controller = "Foo", action = "Index" }); 

} 

從我希望通過這種途徑來生成一個鏈接我的Razor視圖代碼,所以我這樣做:

RouteValueDictionary rd = new RouteValueDictionary(this.Url.RequestContext.RouteData.Values); 
rd["fooId"  ] = "123"; 
rd["fooRevision"] = "4"; 

this.Url.RouteUrl("Foo_Bar", rd); 

但是,這返回null。沒有例外。沒有其他副作用。

調試器顯示rd包含5個命名值:tenantNamecontrolleractionfooIdfooRevision。我還在調試過程中添加了area,以確保它仍然返回null。

我證實路由存在,因爲this.Url.RouteCollection["Foo_Bar"]返回對應於該路由的System.Web.Routing.Route對象。

我試過.NET Source Stepping,並且我能夠將1級別升級到UrlHelper,但是進入GenerateUrl函數失敗,Visual Studio 2015 U2總是對其執行操作。

回答

0

我不得不介入,到.NET Framework的源代碼,以弄清楚這一個 - 先入System.Web.Mvc.dll進入UrlHelper.RouteUrl,然後叫成System.Web.Routing.dll(這是目前在.NET 4.5 System.Web.dll存根)。

答案就在ParsedRoute::Bindhttp://referencesource.microsoft.com/#System.Web/Routing/ParsedRoute.cs

所以,問題是在這條線:

RouteValueDictionary rd = new RouteValueDictionary(this.Url.RequestContext.RouteData.Values); 

這將導致rd從當前請求的上下文複製(繼承)的值,我想這是可取的。我認爲,因爲路線Foo_Bar提供了一個默認的controlleraction參數值,它會始終使用那些優先於rd中的任何值,但我錯了。

傳入UrlHelper.RouteUrlrd包含controlleraction的值,但它們是針對當前請求的,因此與默認值不同。

ParsedRoute::Bind定義是這樣的,它中止如果提供RouteValueDictionary提供爲默認值不同的參數值(見線133至149中ParsedRoute.cs

感覺框架應在這種情況下拋出異常,而不是返回null - 因爲這種行爲似乎沒有很好的記錄 - 尤其是因爲所有的搜索結果都表明問題只是路由不存在或參數傳遞不足 - 在我的情況下,問題是在某種程度上太多參數正在通過

0

A null值表示所請求的值與任何路由都不匹配。由於您還明確指定了路線名稱(其行爲類似於路線表上的過濾器),因此可以肯定地說,路線Foo_Bar與提供的路線值輸入不匹配。

您還沒有提供{tenantName}的默認值(如果沒有合理的默認值,這很好),因此{tenantName}是必需的值。當您提供{tenantName}的值時,URL會正確生成。

RouteValueDictionary rd1 = new RouteValueDictionary(); 
rd1["fooId"] = "123"; 
rd1["fooRevision"] = "4"; 

var url1 = this.Url.RouteUrl("Foo_Bar", rd1); 
// url1 value is null 

RouteValueDictionary rd2 = new RouteValueDictionary(); 
rd2["fooId"] = "123"; 
rd2["fooRevision"] = "4"; 
rd2["tenantName"] = "SomeTenant"; 

var url2 = this.Url.RouteUrl("Foo_Bar", rd2); 
// url2 value is /SomeTenant/foo/123/4 

注: MVC automatically reuses route values from the current request未明確規定。沒有必要明確地將this.Url.RequestContext.RouteData.Values添加到路線集合中。

當然,這意味着你可能沒有明確添加tenantName到路由集合,這取決於您在運行此代碼上下文是否已經擁有它。

+0

即使當我提供e是字典中顯式的'tenantName',它仍然返回null。這很奇怪。 – Dai