2010-04-16 82 views
11

我已經幾乎在這裏問了一個問題:ASP.NET MVC Html.ActionLink維護路由值

asp.net mvc Html.ActionLink() keeping route value I don't want

然而,最終的解決方案是組裝機,純粹而簡單,我真的會想了解爲什麼會發生這種情況,如果有人可以請向我解釋一下?

爲了完整,可以非常容易地重新創建的場景:

  • 創建一個新的MVC的Web應用程序。
  • 運行它。
  • 訪問About選項卡修改URL以讀取/ Home/About/Flib - 顯然,這會將您帶到ID爲'Flib'的行動,我們不關心。

注意,頂部菜單鏈接到關於現在實際上鍊接到/首頁//Flib - 這是錯誤的,據我所看到的,因爲我現在絕對沒有使用網站的鏈接要回的方式/首頁/關於

我真的不明白爲什麼我應該強制修改我的所有Html.ActionLinks,以包含new { id = string.Empty }作爲routevalues,null作爲htmlAttribs。這看起來尤其突出,因爲我已經指定id = 0作爲路線本身的一部分。

希望我在這裏錯過了一招。

回答

12

當你看看源代碼,操作鏈接你發現

<%= Html.ActionLink("LinkText", "Action", "Controller"); %> 

將匹配

public static MvcHtmlString ActionLink(this HtmlHelper htmlHelper, string linkText, string actionName, string controllerName) { 
     return ActionLink(htmlHelper, linkText, actionName, controllerName, new RouteValueDictionary(), new RouteValueDictionary()); 
    } 

現在到目前爲止,這看起來不錯,因爲它正在創造一個新的路徑值字典,以便它不會將當前上下文中的值傳遞給新鏈接,這將會發生。

然而,在代碼進一步下降,其中正在生成的網址:

public static string GenerateUrl(string routeName, string actionName, string controllerName, RouteValueDictionary routeValues, RouteCollection routeCollection, RequestContext requestContext, bool includeImplicitMvcValues) { 
     if (routeCollection == null) { 
      throw new ArgumentNullException("routeCollection"); 
     } 

     if (requestContext == null) { 
      throw new ArgumentNullException("requestContext"); 
     } 

     RouteValueDictionary mergedRouteValues = RouteValuesHelpers.MergeRouteValues(actionName, controllerName, requestContext.RouteData.Values, routeValues, includeImplicitMvcValues); 

     VirtualPathData vpd = routeCollection.GetVirtualPathForArea(requestContext, routeName, mergedRouteValues); 
     if (vpd == null) { 
      return null; 
     } 

     string modifiedUrl = PathHelpers.GenerateClientUrl(requestContext.HttpContext, vpd.VirtualPath); 
     return modifiedUrl; 
    } 

可以看到的RequestContext被引用其中有訪問的RouteData和routeCollections,其中將包含ID數據。當創建VirtualPathForArea,下面一行是其中的id值將出現在您的網址:

internal static VirtualPathData GetVirtualPathForArea(this RouteCollection routes, RequestContext requestContext, string name, RouteValueDictionary values, out bool usingAreas) { 
     if (routes == null) { 
      throw new ArgumentNullException("routes"); 
     } 

     if (!String.IsNullOrEmpty(name)) { 
      // the route name is a stronger qualifier than the area name, so just pipe it through 
      usingAreas = false; 
      return routes.GetVirtualPath(requestContext, name, values); 
     } 

     string targetArea = null; 
     if (values != null) { 
      object targetAreaRawValue; 
      if (values.TryGetValue("area", out targetAreaRawValue)) { 
       targetArea = targetAreaRawValue as string; 
      } 
      else { 
       // set target area to current area 
       if (requestContext != null) { 
        targetArea = AreaHelpers.GetAreaName(requestContext.RouteData); 
       } 
      } 
     } 

     // need to apply a correction to the RVD if areas are in use 
     RouteValueDictionary correctedValues = values; 
     RouteCollection filteredRoutes = FilterRouteCollectionByArea(routes, targetArea, out usingAreas); 
     if (usingAreas) { 
      correctedValues = new RouteValueDictionary(values); 
      correctedValues.Remove("area"); 
     } 

     VirtualPathData vpd = filteredRoutes.GetVirtualPath(requestContext, correctedValues); 
     return vpd; 
    } 

行:

VirtualPathData vpd = filteredRoutes.GetVirtualPath(requestContext, correctedValues); 

需要的虛擬路徑(這只是路線)並返回它。因此,虛擬路徑將是/Home/About/Flib

然後當返回的虛擬路徑下面一行用它來設置客戶端的URL跳轉鏈接:

string modifiedUrl = PathHelpers.GenerateClientUrl(requestContext.HttpContext, vpd.VirtualPath); 

所以幾乎是它看起來像ActionLink的設置使用區域的虛擬路徑,這只是匹配的路線,在這種情況下恰好是默認路線。

+5

@Carl,@amurra:這是不是解決問題或者這只是中無法充分解決的症狀的解釋嗎? – 2011-02-24 20:03:28

+0

@Robert Koritnik - 這只是對ASP.NET MVC 2中發生了什麼的解釋。不知道這段代碼是否隨ASP.NET MVC 3發生了變化。 – amurra 2011-02-24 20:27:40

+0

我不知道,老實說我並不在乎,因爲我也使用MVC2 RTM(因爲我必須使用.net 3.5)。所以我也有這個問題。但我做了這似乎工作:http://stackoverflow.com/questions/3475981/ambient-values-in-mvc2-net-routing/5110032#5110032 – 2011-02-24 20:30:33

3

如果我理解正確,聽起來好像需要註冊第二個「Action Only」路徑並使用Html.RouteLink。首先註冊一個這樣的路線在你的應用程序啓動:

routes.MapRoute("ActionOnly", "{controller}/{action}", new { controller = "Home", action = "Index" }); 

然後,而不是ActionLink的創建這些鏈接中使用:

Html.RouteLink("About","ActionOnly") 
1

如果你要麼不知道值需要加以明確覆蓋或者你只是想避免額外的參數列表,你可以使用像下面這樣的擴展方法。

<a href="@Url.Isolate(u => u.Action("View", "Person"))">View</a> 

實施細節爲in this blog post