【问题标题】:Why do route decorators break routing in ASP.NET MVC 2?为什么路由装饰器会破坏 ASP.NET MVC 2 中的路由?
【发布时间】:2009-11-04 02:39:03
【问题描述】:

我有一个使用 MVC 2 Preview 2 的 Web 应用程序,并且在注册了所有路由之后,我需要将每个路由包装在一个装饰器中,使其更进一步。问题是,这样做会破坏路由。最终发生的是 GetVirtualPath 方法将错误地匹配应用程序中的其他区域(我使用的是单项目区域)。装饰器是否做了任何有用的事情都没有关系。只需使用以下 passthrough 即可破解它。

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

【问题讨论】:

    标签: asp.net asp.net-mvc routing


    【解决方案1】:

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

    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;
            }
        }
    

    【讨论】:

    • 感谢您的努力。实施 IRouteWithArea 并不能完全解决问题,但它可能会将我带入一个新的方向。谢谢。
    • 装饰器似乎不止一次地包裹了路线。我已经编辑了我的答案,提供了代码来实现一个可行的解决方案,但理想情况下我想找出为什么会发生这种情况,因为这很奇怪。
    • 这绝对是问题的答案。我没有发现产卵装饰器问题。这是一些奇怪的行为,或者是不了解其发生原因的预期行为。
    【解决方案2】:

    如果你装饰 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);
        }
    }
    

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

    希望对你有所帮助。

    【讨论】:

    • 我不能使用 Route 而不是 RouteBase,因为 RouteCollection 是 RouteBase 的集合。在将问题发布到此处之前,我已经使用 Reflector 和 MVC 2 源代码来尝试推断问题。您的其他建议(清除收藏?)无效。
    猜你喜欢
    • 2012-06-19
    • 2019-06-28
    • 1970-01-01
    • 2011-08-05
    • 1970-01-01
    • 2016-06-27
    • 1970-01-01
    • 2013-06-02
    • 2016-10-18
    相关资源
    最近更新 更多