2009-11-04 54 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