【问题标题】:MVC routing questionMVC 路由问题
【发布时间】:2011-07-31 22:52:12
【问题描述】:

我想设置路由如下:

/Profile/Edit -> 编辑操作的路径

/Profile/Add -> 添加操作的路由

/Profile/username -> 使用参数用户名路由到索引操作,因为操作用户名不存在。

所以我希望将第二个参数解析为控制器操作,除非不存在具有该名称的控制器;然后它应该路由到默认索引页面并使用 url 部分作为 id。

可能吗?

【问题讨论】:

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


    【解决方案1】:

    一切皆有可能。但是,为什么不直接将 /profile 设为您的根目录?

    如果这不可能,您可能需要硬编码您的操作路线。

    【讨论】:

    • 嗯,是的,有点愚蠢,但我并没有真正想到这一点:) 我可能会这样,这会让事情变得更容易。
    【解决方案2】:

    Matt 的解决方案可以帮助您完成 90% 的工作。但是,不要使用路由约束来排除操作名称,而是使用路由约束来仅包含有效的用户名,如下所示:

    public class MustMatchUserName : IRouteConstraint 
    { 
    
        private Users _db = new UserEntities(); 
    
        public MustMatchUserName() 
        { } 
    
        public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection) 
        { 
            return _db.Users.FirstOrDefault(x => x.UserName.ToLower() == values[parameterName].ToString().ToLower()) != null; 
        } 
    } 
    

    然后,正如 Matt 指出的那样,在用户创建过程中,您必须强制执行一个规则,即您的 ActionNames 对用户名无效。

    辅导员

    【讨论】:

      【解决方案3】:

      您可以像这样在路由约束中使用正则表达式

      routes.MapRoute(
          "UserProfileRoute",
          "Profile/{username}",
          new { controller = "Profile", action = "Index" },
          new { username = "(?i)(?!edit$|add$)(.*)" });
      

      这将匹配像 /profile/addendum /profile/someusername 这样的网址,并将忽略 /profile/edit/profile/add

      【讨论】:

        【解决方案4】:

        这是实现此目的的一种方法:

        在 Global.asax.cs 中创建这些路线:

         routes.MapRoute("UserProfileRoute", "Profile/{username}",
            new { controller = "Profile", action = "Index" });
         routes.MapRoute("DefaultProfileRoute", "Profile/{action}", 
            new { controller = "Profile", action = "SomeDefaultAction" });
        

        这将按预期匹配 /Profile/someUsername。但是对于所有其他操作,它将失败。现在假定所有操作名称都是用户名。对此的快速解决方法是将 IRouteConstraint 添加到第一条路由:

         routes.MapRoute("UserProfileRoute", "Profile/{username}", 
             new { controller = "Profile", action = "Index" }, 
             new { username = new NotAnActionRouteConstraint() });
         routes.MapRoute("DefaultProfileRoute", "Profile/{action}", 
            new { controller = "Profile", action = "SomeDefaultAction" });
        
         public class NotAnActionRouteConstraint : IRouteConstraint 
         {
            public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
            {
                string value = values[parameterName].ToString();
        
                            // it is likely parameterName is not cased correctly,
                            // something that would need to be 
                            // addressed in a real implementation
                return typeof(ProfileController).GetMethod(parameterName,
                                 BindingFlags.Public | BindingFlags.Instance) == null;
            }
         }
        

        但是,这有点难看。希望有人知道更好的解决方案。

        当您的某个用户选择与操作相同的名称时,您也会遇到问题 :)

        【讨论】:

        • 是的,关于最后一条评论,我将实现一些反射逻辑,以防止用户选择等于操作的用户名。
        • 顺便说一下,Facebook 也这样做了,我可以通过 facebook.com/username 打开我的 Facebook 个人资料。对我的名字来说不是那么危险,但其他人可能更棘手。我想知道如果他们想在用户已经声明的地址上创建文件夹或任何内容,他们会怎么做。
        猜你喜欢
        • 1970-01-01
        • 2016-11-09
        • 2013-11-13
        相关资源
        最近更新 更多