代码之家  ›  专栏  ›  技术社区  ›  Daniel Crenna

为什么路由装饰器会破坏ASP.NET MVC 2中的路由?

  •  6
  • Daniel Crenna  · 技术社区  · 15 年前

    我有一个使用MVC 2 Preview 2的Web应用程序,在注册了所有路由之后,我需要将每个路由包装在一个装饰器中,再沿着链进一步。问题是,这样做会破坏路由。最终的结果是getvirtualpath方法将错误地匹配应用程序中的其他区域(我使用的是单个项目区域)。不管装饰师是否做了什么有用的事情。您只需要使用下面的传递就可以打破它。

    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 . 在复制过程中,路径装饰器被注释掉了。重新注释它将中断路由,并且第一个虚拟区域的路由数据将匹配通常只正确匹配相应命名空间的链接。

    2 回复  |  直到 15 年前
        1
  •  5
  •   LondonBasedEngineer    15 年前

    我认为这取决于区域使用datatokens字典来存储区域/名称空间信息的方式。当您从RouteBase继承时,可能需要实现 IRouteWithArea 接口,因为您没有路由所具有的数据令牌。

    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;
            }
        }
    
        2
  •  0
  •   Venemo    15 年前

    如果装饰路由类而不是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);
        }
    }
    

    我还建议使用Reflector签出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));
    }
    

    我非常希望它能有所帮助。