第二节:各种路由约束(动态路由、静态路由、组合路由、正则约束、命名空间约束、区域内路由)

一. 什么是路由

   路由是约束URL的一组规范,那么什么是URL呢?通俗的来说URL是一个地址,通过该地址,用户可以访问Web网站或者下载服务器上的文件。

     比如下面就是两组URL:

    http://www.cnblogs.com/yaopengfei/p/7828441.html

    http://www.cnblogs.com/yaopengfei/p/7828441

  显然我们喜欢第二组,省略.html,会使该地址看起来更加简洁,更加友好,利于SEO优化。

  那么我们怎么实现这个简单的需求呢?

  答案是:通过【路由】配置,所以现在我们似乎有点清晰了,路由可以规定URL的特殊格式,使其达到特殊效果。

  在ASP.NET MVC框架中,通过路由配置URL,使用户的URL请求可以映射到Controller下的action方法中,执行相应操作,并接受URL中传过来的参数,在MVC5框架中,在【RouteConfig.cs】类中进行路由规则的配置,如下图:

    

 

二. 从源码的角度分析路由

   我们进入【RouteConfig】类中,发现核心代码是调用【RouteCollection】类下的MapRoute方法,F12看源码得知,MapRoute方法是RouteCollectionExtensions类的给【RouteCollection】类扩展方法的方法,并且有多个重载,如下图:

  下面分析一下参数的含义:

    (1) name:  要映射的路由的名称。

    (2) url:  路由的 URL 模式,可以自定义路由的格式,可以写静态路由,也可以写动态路由、组合路由等。

    (3) defaults:  一个包含默认路由值的对象,书写路由的默认值。

    (4) constraints: 一组表达式,可以使用正则指定 url 参数值的约束。

    (5) namespaces: 应用程序的一组命名空间,可以缩小检索路由对象匹配的范围。

  底层源码,有兴趣可以看一下:

 1  public static Route MapRoute(this RouteCollection routes, string name, string url, object defaults, object constraints, string[] namespaces)
 2         {
 3             if (routes == null)
 4             {
 5                 throw new ArgumentNullException("routes");
 6             }
 7             if (url == null)
 8             {
 9                 throw new ArgumentNullException("url");
10             }
11             Route route = new Route(url, new MvcRouteHandler()) {
12                 Defaults = CreateRouteValueDictionaryUncached(defaults),
13                 Constraints = CreateRouteValueDictionaryUncached(constraints),
14                 DataTokens = new RouteValueDictionary()
15             };
16             ConstraintValidation.Validate(route);
17             if ((namespaces != null) && (namespaces.Length > 0))
18             {
19                 route.DataTokens["Namespaces"] = namespaces;
20             }
21             routes.Add(name, route);
22             return route;

 

三. MVC中的几类路由及其规则

1. 动态路由

1        routes.MapRoute(
2                 name: "Default",    //路由名称
3                 url: "{controller}/{action}/{id}",   //路由规则
4                 defaults: new { controller = "First", action = "Index1", id = UrlParameter.Optional }  //默认值,当Controller或action为空(省略)的时候调用
5             );

分析:路由规则为 {controller}/{action}/{id} ,其中 {controller}、{action}、{id}为三个参数,/ 为格式分割符号,defaults中声明的是默认路由,所以下面的测试结果:

http://localhost:7559/

http://localhost:7559/First

http://localhost:7559/First/index1

http://localhost:7559/First/Index1/2

都会跳转到Index1的页面。

  变种:将上面的代码的URL分割符号稍微调整一下

1        routes.MapRoute(
2                name: "Default9",    //路由名称
3                url: "{controller}/{action}-{id}",   //路由规则
4                defaults: new { controller = "First", action = "Index1", id = UrlParameter.Optional }  //默认值,当Controller或action为空(省略)的时候调用
5            );

  请求地址就变成了:

http://localhost:7559/                                               【无法访问】

http://localhost:7559/First                                        【404找不到】

http://localhost:7559/First/index1                            【404找不到】

http://localhost:7559/First/Index1-1                         【可以访问】

 

2. 静态路由

1         routes.MapRoute(
2                 name: "Default2",    //路由名称
3                 url: "Ypf",   //路由规则,不区分大小写,当输入“ypf”时,会自动跳转到下面的地址
4                 defaults: new { controller = "First", action = "Index1", id = UrlParameter.Optional }  //默认值,当Controller或action为空的时候调用
5             );

静态路由:url中是一个静态值,访问的URL只有输入这个静态值,才能访问下面default中的默认值。

测试地址如下:

http://localhost:7559/                                            【无法访问】

http://localhost:7559/ypf                                      【 跳转到index1页面】

http://localhost:7559/First/index1                       【无法访问】

补充一下:MapRoute方法是可以不需要写参数名的,就像正常的调用方法一样,所以上面的代码可以改写:

1             routes.MapRoute(
2                 "Default3",    //路由名称
3                 "Ypf",   //路由规则,不区分大小写,当输入“Ypf”时,会自动跳转到下面的地址
4                  new { controller = "First", action = "Index1", id = UrlParameter.Optional }  //默认值,当Controller或action为空的时候调用
5             );

 

3. 组合路由

1       routes.MapRoute(
2              "Default4",    //路由名称
3              "Ypf/{action}",   //路由规则,不区分大小写,规则相符的时候,会自动跳转到下面的地址
4               new { controller = "First", action = "Index1" }
5          );

所谓的组合路由,就是静态路由和动态路由相互组合使用,测试地址如下:

  http://localhost:7559/             【无法访问】       (分析:因为不满足路由规则,没有输入ypf)

  http://localhost:7559/ypf              【 跳转到index1页面】  

  http://localhost:7559/ypf/index1             【 跳转到index1页面】

  http://localhost:7559/Ypf/hh              【404找不到】        (满足路由规则,但是没有hh这个action,所以404)

  http://localhost:7559/ypf/First/index1       【404找不到】        (满足路由规则,但这里把First当做action,并没有这个action,所以404)

 

4. 正则约束

1        routes.MapRoute(
2                "Default5",
3                 "{controller}/{action}_{Year}_{Month}_{Day}",
4                 new { controller = "First", action = "Index1", id = UrlParameter.Optional },
5                 new { Year = @"^\d{4}", Month = @"\d{2}", Day = @"\d{2}" }
6             );//正则路由

所谓的正则约束,是指可以对URL中的参数使用正则表达式进行约束,上述代码约束了Year必须是四位数字,Month和Day必须是两位数字。

测试地址:

  http://localhost:7559/first/index1_2018_09_01         【跳转到index1页面】

  http://localhost:7559/first/index1         【无法访问】       (分析:因为不满足路由规则,没有输入{Year}_{Month}_{Day} 的参数)

  http://localhost:7559/first/            【无法访问】       (分析:因为不满足路由规则,没有输入{Year}_{Month}_{Day} 的参数

  http://localhost:7559/                【无法访问】        (分析:因为不满足路由规则,没有输入{Year}_{Month}_{Day} 的参数

 

5. 命名空间约束

1         routes.MapRoute(
2                  name: "Default6",
3                  url: "{controller}/{action}/{id}",
4                  defaults: new { controller = "Third", action = "Index", id = UrlParameter.Optional },
5                  namespaces: new string[] { "Ypf.MVC5" }
6             );

所谓的命名空间约束,即限定匹配范围路由的检索范围,提高检索速度。

特别注意:不能从外层控制器直接跳转到内层Area内的控制器!!

测试地址:以下三个访问地址,都会跳转到index1页面

  http://localhost:7559/

  http://localhost:7559/First

  http://localhost:7559/First/index1

 

6. Area区域内的路由

 1    public override void RegisterArea(AreaRegistrationContext context) 
 2         {
 3             //原路由
 4             //context.MapRoute(
 5             //    "TestOne_default",
 6             //    "TestOne/{controller}/{action}/{id}",
 7             //    new { action = "Index", id = UrlParameter.Optional }
 8             //);
 9 
10             //结合命名空间进行路由改造
11             context.MapRoute(
12                this.AreaName + "_default",
13                this.AreaName + "/{controller}/{action}/{id}",
14                new { area = this.AreaName, controller = "Sys_Admin", action = "Index", id = UrlParameter.Optional },
15                new string[] { "Ypf.MVC5.Areas." + this.AreaName + ".Controllers" }
16            );
17 
18         }

  指MVC5框架中Area区域单独的一套路由规则,我们可以结合区域内的原路由,进行改造一番,如上述代码。

 

 

posted @ 2017-11-23 16:34  Yaopengfei  阅读(3813)  评论(4编辑  收藏  举报