【问题标题】:ASP.NET MVC catch-all routingASP.NET MVC 包罗万象的路由
【发布时间】:2011-10-13 21:09:52
【问题描述】:

我在 StackOverflow 上阅读了一些关于此的主题,但无法使其正常工作。我在 Global.asax 的 RegisterRoutes 末尾有这个。

routes.MapRoute(
            "Profile",
            "{*url}",
            new { controller = "Profile", action = "Index" }
            );

基本上,我想要实现的是让 mydomain.com/Username 指向我的会员个人资料页面。我必须如何设置我的控制器和 RegisterRoutes 才能使其正常工作?

目前 mydomain.com/somethingthatisnotacontrollername 收到 404 错误。

【问题讨论】:

  • 如果您在上面的路由之前配置了默认的{controller}/{action}/{id} 路由,它将真正匹配任何 URL - 在这种情况下,控制器 = somethingthatisnotacontrollername,操作 = Index,并且 id 为空。 .routes 从上到下匹配,因此在默认路径下定义任何内容都没有什么意义...

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


【解决方案1】:

适用于您的情况但不推荐的解决方案

您的应用程序中有一组预定义的控制器(通常少于 10 个),因此您可以对控制器名称进行限制,然后将其他所有内容路由到用户配置文件:

routes.MapRoute(
    "Default",
    "{controller}/{action}/{id}",
    new { controller = "Home", action = "Index", id = UrlParameter.Optional },
    new { controller = "Home|Admin|Reports|..." }
);
routes.MapRoute(
    "Profile",
    "{username}/{action}",
    new { controller = "Profile", action = "Details" }
);

但如果某些用户名与您的控制器名称相同,这将不起作用。根据经验结束的经验数据,这是一个很小的可能性,但它不是 0% 的机会。当用户名与某个控制器相同时,它自动意味着它将由第一个路由处理,因为约束不会失败。

推荐解决方案

最好的方法是将 URL 请求设置为:

www.mydomain.com/profile/username

为什么我推荐它是这样的?因为这将使它更简单、更干净,并允许拥有多个不同的个人资料页面:

  • 详情www.mydomain.com/profile/username
  • 设置www.mydomain.com/profile/username/settings
  • 留言www.mydomain.com/profile/username/messages

这种情况下的路由定义如下:

routes.MapRoute(
    "Profile",
    "Profile/{username}/{action}",
    new { controller = "Profile", action = "Details" }
);
routes.MapRoute(
    "Default",
    "{controller}/{action}/{id}",
    new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);

【讨论】:

  • “/Profile/Username”解决方案可能是最合理的方法,但不适用于这种特殊情况。您的第一个(不推荐)解决方案效果很好。我显然需要对用户选择的用户名采取额外的预防措施。谢谢。
  • @David:不用担心,感谢您接受我的回答。如果您需要多个个人资料页面,我已经在第一个解决方案中更新了路线定义,因此您也可以像在第二个解决方案中一样拥有这些。
【解决方案2】:

拥有与mydomain.com/Username 匹配的东西并不能真正起作用,因为路由引擎无法区分它们

mydomain.com/someusername

mydomain.com/controllername

可能可能是,如果您的用户名方案具有一组独特的属性,即 9 位数字序列,您可以定义一个路由来检查看起来像用户名的东西。

routes.MapRoute("",
        "UserRoute",
        "{username}",
        new { controller = "Profile", action = "Index"},
         new { {"username", @"\d{9}"}}
       );

关键点是,您需要为路由引擎提供某种方式来区分用户名和标准控制器操作

您可以了解更多关于约束here

【讨论】:

    【解决方案3】:

    我的项目有这样的要求。我所做的是创建如下的路线约束:

    public class SeoRouteConstraint : IRouteConstraint
    {
        public static HybridDictionary CacheRegex = new HybridDictionary();
        private readonly string _matchPattern = String.Empty;
        private readonly string _mustNotMatchPattern;
    
        public SeoRouteConstraint(string matchPattern, string mustNotMatchPattern)
        {
            if (!string.IsNullOrEmpty(matchPattern))
            {
                _matchPattern = matchPattern.ToLower();
                if (!CacheRegex.Contains(_matchPattern))
                {
                    CacheRegex.Add(_matchPattern, new Regex(_matchPattern));
                }
            }
    
            if (!string.IsNullOrEmpty(mustNotMatchPattern))
            {
                _mustNotMatchPattern = mustNotMatchPattern.ToLower();
                if (!CacheRegex.Contains(_mustNotMatchPattern))
                {
                    CacheRegex.Add(_mustNotMatchPattern, new Regex(_mustNotMatchPattern));
                }
            }
        }
    
        public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
        {
            var matchReg = string.IsNullOrEmpty(_matchPattern) ? null : (Regex)CacheRegex[_matchPattern];
            var notMatchReg = string.IsNullOrEmpty(_mustNotMatchPattern) ? null : (Regex)CacheRegex[_mustNotMatchPattern];
    
            var paramValue = values[parameterName].ToString().ToLower();
    
            return IsMatch(matchReg, paramValue) && !IsMatch(notMatchReg, paramValue);
        }
    
        private static bool IsMatch(Regex reg, string str)
        {
            return reg == null || reg.IsMatch(str);
        }
    }
    

    然后在注册路由方法中:

    routes.MapRoute("",
        "UserRoute",
        "{username}",
        new { controller = "Profile", action = "Index"},
         new { username = new SeoRouteConstraint(@"\d{9}", GetAllControllersName())}
       );
    

    GetAllControllersName 方法将返回您项目中的所有控制器名称,以 | 分隔。 :

    private static string _controllerNames;
    private static string GetAllControllersName()
    {
        if (string.IsNullOrEmpty(_controllerNames))
        {
            var controllerNames = Assembly.GetAssembly(typeof(BaseController)).GetTypes().Where(x => typeof(Controller).IsAssignableFrom(x)).Select(x => x.Name.Replace("Controller", ""));
    
            _controllerNames = string.Join("|", controllerNames);
        }
        return _controllerNames;
    }
    

    【讨论】:

      猜你喜欢
      • 2016-08-20
      • 2011-04-02
      • 1970-01-01
      • 2011-02-12
      • 2014-05-05
      • 2021-08-25
      • 1970-01-01
      • 1970-01-01
      • 2021-09-09
      相关资源
      最近更新 更多