2014-03-27 61 views
4

工作,我需要的文化添加到URL支持本地化在我的asp.net MVC應用程序使用的URL,如:sample.com/ EN /約
sample.com/ EN /產品/ 2342Asp.Net MVC路由未如預期在5.1

我最近升級我的應用程序從MVC 5.0到5.1,但如預期的路由沒有工作,所以我創建了一個新的asp.net的MVC 5.0測試應用程序,並得到了文化只需幾分鐘即可在網址中顯示出來。但是,只要我將此測試應用程序升級到MVC 5.1,鏈接中不再生成文化,並且如果您手動將它輸入到URL中,則會出現404錯誤。

我壓縮了我的5.0和5.1測試應用程序here。我需要幫助理解爲什麼這不適用於MVC 5.1以及如何糾正它。也許我對路由的理解是有缺陷的,或者這對5.1是一個合法的錯誤?

在這個測試應用程序的主頁/關於行動已應用[Route("about")]路由屬性和它的預期,在生成鏈接,這條路應該是localhost/en/about而是它只是localhost/about。如果您在地址欄中輸入localhost/en/about,您將在Mvc 5.1測試應用程序中收到404錯誤。

下面是相關的代碼,不會在MVC 5.0工作:

public class RouteConfig 
{ 
    private const string STR_Culture = "culture"; 
    public static void RegisterRoutes(RouteCollection routes) 
    { 
     routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); 
     routes.LowercaseUrls = true; 
     routes.MapMvcAttributeRoutes(); 
     routes.MapRoute(
      name: "Default", 
      url: "{culture}/{controller}/{action}/{id}", 
      defaults: new { culture = "en", controller = "Home", action = "Index", id = UrlParameter.Optional } 
     ); 

     foreach (var item in routes) 
     { 
      // this works in MVC 5.0 
      if (item is Route) 
      { 
       var route = item as Route; 
       if (route.Url.IndexOf("{" + STR_Culture + "}") == -1) 
        route.Url = String.Format("{{{0}}}/{1}", STR_Culture, route.Url); 

       //AddCulture(route.Defaults); 
      } 
     } 
    } 
    private static void AddCulture(RouteValueDictionary dictionary) 
    { 
     if (dictionary == null) 
      dictionary = new RouteValueDictionary(); 

     if (dictionary.ContainsKey(STR_Culture) == false) 
      dictionary.Add(STR_Culture, "en"); 
    } 
} 
+0

在'for-loop'和對方法的調用中,你是否簡單地將文化默認爲「en」?無法分辨出該做什麼。 –

回答

1

好了,想通了這一點。 MVC 5.1引入了重大變化。在上面的代碼中,有一個foreach循環,它動態地改變所有路由URL以追加「{culture} /」佔位符。例如路線about變成{culture}/about等等。

這適用於5.0,因爲路由類型爲System.Web.Routing.Route。在5.1中,他們引入了一堆額外的類。其中之一稱爲LinkGenerationRoute,用於通過屬性路由應用的所有路由。本課程保留原始路線的私人只讀參考,該路線在首次致電routes.MapMvcAttributeRoutes();期間進行,該路線註冊基於屬性的路線。然後這個類通過將它的單獨屬性發送到它繼承的基類來克隆該Route:Route

在foreach循環中,我切實改變基礎CLASSE的URL,但不內部參考路線對象LinkGenerationRoute持有上。結果是框架中現在有兩個Route實例,我們只能在創建後修改基礎實例。不幸的是,內部路徑(_innerRoute)用於獲取虛擬路徑,因此導致鏈接被錯誤地生成,因爲它在創建後無法修改。

看起來像唯一的方法是在每個路徑定義中手動添加此佔位符。例如 [Route("{culture}/about")],[Route("{culture}/contact")],[Route("{culture}/product/{productId:int}")]等等。

在這一天結束的時候,我看不出有什麼意見可以在這個班級舉辦路線的內部參考。應該使用當前實例。例如this.GetVirtualPath(requestContext, values);

internal class LinkGenerationRoute : Route 
{ 
    private readonly Route _innerRoute; // original route cannot be modified 

    public LinkGenerationRoute(Route innerRoute) 
     : base(innerRoute.Url, innerRoute.Defaults, innerRoute.Constraints, innerRoute.DataTokens, 
     innerRoute.RouteHandler) // original route is effectively cloned by sending individual properties to base class 
    { 
     if (innerRoute == null) 
     { 
      throw Error.ArgumentNull("innerRoute"); 
     } 

     _innerRoute = innerRoute; 
    } 

    public override RouteData GetRouteData(HttpContextBase httpContext) 
    { 
     // Claims no routes 
     return null; 
    } 

    public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values) 
    { 
     // internal route is used for getting the virtual path. fail.. 
     return _innerRoute.GetVirtualPath(requestContext, values); 
    } 
} 
+0

我不確定我瞭解您的解決方案。在我們的例子中,我們沒有使用文化,但RouteConfig在MapMvcAttributeRoutes()調用上失敗,出現此錯誤::無法調用操作方法'System.Web.Mvc.PartialViewResult ErrorView [T](T,System.String,System。 String,System.String)'on controller'name here',因爲action方法是一個通用的方法。你知道我們應該怎麼做才能解決它? – Naomi

+0

他們爲什麼會改變這一點。使用內部屬性並以此格式獲得什麼收益?您的第一個解決方案非常優雅,並且建立在整個ASP.NET堆棧的可擴展性之上。這個解決方案是朝相反方向邁出的一步 – Korayem