2009-11-04 83 views
6

我有一個使用MVC 2 Preview 2的web應用程序,並且在所有的路由都被註冊之後,我需要將每個路由封裝在鏈中的裝飾器中。問題是,這樣做會破壞路由。最終發生的是GetVirtualPath方法將錯誤地匹配應用程序中的其他區域(我正在使用單個項目區域)。裝飾器是否有用或無用並不重要。使用下面的傳遞是你需要打破它。爲什麼路由裝飾器在ASP.NET MVC 2中斷開路由?

public class RouteDecorator: RouteBase 
{ 
    readonly RouteBase _route; 

    public RouteDecorator(RouteBase route) 
    { 
     _route = route; 
    } 

    public override RouteData GetRouteData(HttpContextBase context) 
    { 
     return _route.GetRouteData(context); 
    } 

    public override VirtualPathData GetVirtualPath(RequestContext context, RouteValueDictionary values) 
    { 
     return _route.GetVirtualPath(context, values); 
    } 
} 

我在註冊所有路由後,在一個簡單的循環中分配裝飾器。

var routes = RouteTable.Routes; 
for (var i = 0; i < routes.Count; i++) 
{ 
    routes[i] = new RouteDecorator(routes[i]); 
} 

如何在不破壞路徑和區域的情況下安全地插入裝飾器?

我有複製解決方案to download here。在再現中,路由裝飾器被註釋掉。重新註釋它會斷開路由,第一個虛擬區域的路由數據將匹配通常只能正確匹配相應名稱空間的鏈接。

回答

5

我認爲這取決於區域使用DataToken字典存儲區域/名稱空間信息的方式。由於您從RouteBase繼承,您可能還需要實現接口IRouteWithArea,因爲您沒有Route所具有的DataToken。

的ActionLink的助手似乎間接調用此因此需要新的接口:

public static string GetAreaName(RouteBase route) 
{ 
    IRouteWithArea area = route as IRouteWithArea; 
    if (area != null) 
    { 
     return area.Area; 
    } 
    Route route2 = route as Route; 
    if ((route2 != null) && (route2.DataTokens != null)) 
    { 
     return (route2.DataTokens["area"] as string); 
    } 
    return null; 
} 

[編輯 - 2009-11-12] 我相信下面將解決這個問題,作爲裝飾似乎要結束了包裹路線不止一次:

上裝飾附加屬性:

public RouteBase InnerRoute 
     { 
      get 
      { 
       return _route; 
      } 
     } 

接口實現:

public string Area 
     { 
      get 
      { 

       RouteBase r = _route; 
       while (r is RouteDecorator) 
        r = ((RouteDecorator) r).InnerRoute; 
       string s = GetAreaToken(r); 
       if (s!= null) return s; 
       return null; 
      } 
     } 

     private string GetAreaToken(RouteBase r) 
     { 
      var route = r as Route; 
      if (route != null && route.DataTokens !=null && route.DataTokens.ContainsKey("area")) 
      { 
       return (route.DataTokens["area"] as string); 
      } 
      return null; 
     } 
    } 
+0

感謝您的努力。實施IRouteWithArea並不能糾正問題,但它可能會讓我邁向一個新的方向。謝謝。 – 2009-11-10 18:58:08

+0

裝飾者似乎最終不止包裝路線。我編輯了我的答案,提供了實現工作解決方案的代碼,但我最好想知道爲什麼會發生這種情況,因爲它很奇怪。 – 2009-11-12 15:59:10

+0

這絕對是問題的答案。我沒有捕捉到產卵裝飾者的問題。這是一些奇怪的行爲,或者是對缺乏理解爲什麼會發生的預期行爲。 – 2009-11-12 18:13:22

0

如果裝飾Route類而不是RouteBase,會發生什麼?

的是這樣想:

public class RouteDecorator: Route 
{ 
    readonly Route _route; 

    public RouteDecorator(Route route) 
    { 
     _route = route; 
    } 

    public override RouteData GetRouteData(HttpContextBase context) 
    { 
     return _route.GetRouteData(context); 
    } 

    public override VirtualPathData GetVirtualPath(RequestContext context, RouteValueDictionary values) 
    { 
     return _route.GetVirtualPath(context, values); 
    } 
} 

我也建議檢查出System.Web.Routing.dll與反射器,它可能會給你正在發生什麼的洞察力。

而且也,會發生什麼,如果你這樣做:

var routes = RouteTable.Routes.ToList(); 
RouteTable.Routes.Clear(); 
//or, alternatively, if the above doesn't work: 
//RouteTable.Routes = new RouteCollection(); 
foreach (var r in routes) 
{ 
    RouteTable.Routes.Add(new RouteDecorator(r)); 
} 

我非常希望它能幫助。

+0

我不能使用Route而不是RouteBase,因爲RouteCollection是RouteBase的集合。我已經使用Reflector和MVC 2源代碼在嘗試在發佈之前推導出問題。您的其他建議(清除館藏?)不起作用。 – 2009-11-11 19:31:13