Route@书写规则的总结

路由书写规则的总结

概念:Routing System由一组路由组成,每一个路由规则可以匹配一种类型的URL,在请求过来的时候,Ruting ystem 就用它来处理这个URL,路由的任务就是匹配URL,并且将其中的参数值取出来,路由组册的方法在app_Start 的时候就调用了。

 

 

路由中Segment的概念:

Route@书写规则的总结

上面这个URL的路由规则可以是:routes.MapRoute("MyRoute", "{controller}/{action}");

 

路由匹配的一般规则:                                               

1、默认情况下我们写的路由的Segment的个数与被匹配的URL的Segment的个数是一致的,否者不会被匹配。

2、匹配原则: 当我们有多条路由的时候,路由的匹配是有顺序的,一般情况下先定义的路由先进行匹配,成功了以后,后面的路由就不匹配了,如果没有成功就接着匹配后面的路由,因此我们定义路由的时候最好,顺序最好遵循这样的规则:将特殊情况都放在前面定义,范围广德路由放在后面匹配。

3、路由的默认值比路由的约束条件先执行(这两者后面会讲到)

4、默认情况下会先在磁盘上找与URL匹配的静态文件,如果找到就不会匹配路由了。

 

注:如果我们的路由系统只有上面这个一个路由的规则的话,我们运行程序的时候就会报错,因为我们的默认页面请求的URL是没有Segmen的,因此不会被匹配到,这个就涉及到我们后面会讲到的默认值的问题了。

 

 

 

 

 

路由默认值 :                                                       

有2个Segments的pattern想要匹配有1个或没有SegmentsURL的时候,可以为pattern加上默认值,如下:

        routes.MapRoute("MyRoute", "{controller}/{action}", new {controller="Home", action="Index"});

MapRoute的第三个参数就是在设置默认值,这时候就可以将默认页面设置为Home/Index

 

 

带有静态segment的路由:                                            

routes.MapRoute("MyRoute", "Hu/{controller}/{action}", new {controller="Home", action="Index"});

这个pattern中的开头的Hu没有用{}包起来,说明 Hu 是静态的,这样的结果是:

这个URL必须是以Hu开头的

 

 

Segment中混有静态部分的路由:                                               

routes.MapRoute("MyRoute", "Hu{controller}/{action}");

 

 

带有自定义Segment的路由:                                             

routes.MapRoute("MyRoute", "{controller}/{action}/{id}",new { controller = "Home", action = "Index",id = "DefaultId" });

上面这个pattern中有一个自定义的Segment——id,同样,我们也可以为他添加默认值。

 

 

 

带有可选的Segment变量的路由:                                        

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

在我们为Segment设置默认值以后我们的URL中没有这个Segment也会被匹配到,但是这时候id还是会被添加一个默认的值,有些人特别注重模块之间解耦,那么我们就可以Segment设置为可选的Segment,这样的话即使URL即使没有该Segment也可以被匹配到,而且不会被设置默认值。

 

 

可变长度的路由:                                                       

routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}",new { controller = "Home", action = "Index",id = UrlParameter.Optional });

前面3个Segment会分别匹配给controller/action/id,剩下的部分会全部匹配给catchcall,这样就可以匹配任意长度的URL了。

 

 

 

 

有同名的Controller的解决办法:                                      

URL匹配成功以后,应用程序会到项目中查找符合名称的Controller,如果找到两个同名的符合条件的Controller就会报错,解决如下:

routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = "1" }, new[]{"Route_Study.AdditionalControllers"});

条件:两个同名的controller在不同的目录下,以上处理的实质是在调用 Maproute方法时,再加一个参数,参数是在给方法指定一个命名空间(一个文件夹),制定以后的效果是:

URL匹配成功后,程序先到指定命名空间中查找controller,查找到以后就不会继续查找了,如果查找不到,就会到其他的命名空间这中查找。

 

只在制定的文件夹中查找controller:

有一种情况是:我们只需要在特定的命名空间下查找,即使找不到,我们也不会到其他的命名空间查找,这时的pattern为:

Route myRoute = routes.MapRoute("AddContollerRoute",                                       //路由名

"Home/{action}/{id}/{*catchall}",                                                                              //路由规则

new { controller = "Home", action = "Index",id = UrlParameter.Optional },       //默认值的设置

new[] { "URLsAndRoutes.AdditionalControllers" });                                                     //设置命名空间

myRoute.DataTokens["UseNamespaceFallback"] = false;                                             //只在其他命名空间中查找

 

 

 

 

带有条件约束的路由:

带有正则表达式约束的路由:                                            

public static void RegisterRoutes(RouteCollection routes) {

routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}",                                    //路由名、基本路由规则

new { controller = "Home", action = "Index", id = UrlParameter.Optional },                      //默认值

new { controller = "^H.*", action = "^Index$|^About$"},                                                                //约束

new[] { "URLsAndRoutes.Controllers"});                                                                                                        //指定命名空间

}

我们首相要知道的是默认值是在约束的前面的执行的,所以当有一个URL"/"过来的话,首先是各个Segment得到默认值,然后是看是否符合约束,

 

 

 

HTTP 请求的Method属性的限定:                                     

public static void RegisterRoutes(RouteCollection routes) {

routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}",

new { controller = "Home", action = "Index", id = UrlParameter.Optional },

new { controller = "^H.*", action = "Index|About",

httpMethod = new HttpMethodConstraint("GET") },                                                   //URLMethod进行约束

new[] { "URLsAndRoutes.Controllers" });

}

路由的自定义的约束规则:

 

 

磁盘文件请求 路由匹配的顺序:                                      

MVC中,并不是所有的请求都是在请求一个controller中的一个Action

在默认情况下,当一个请求过来的时候,不会马上将URL与路由进行匹配,而是判断磁盘上是否有与其对应的物理文件,如果有就返回物理文件,而路由就不会用到了,我们通过将routes.RouteExistingFiles属性设置成true,来改变磁盘文件匹配的顺序,如下:

public static void RegisterRoutes(RouteCollection routes) {

routes.RouteExistingFiles = true;                                                  //改变顺序

routes.MapRoute("ChromeRoute", "{*catchall}",

new { controller = "Home", action = "Index" },

new {customConstraint = new UserAgentConstraint("Chrome")},

new[] { "UrlsAndRoutes.AdditionalControllers" });

要使URL先与路由进行匹配,然后与磁盘上的文件进行匹配,我们还需要对IIS进行配置,具体方法

请看《pro_asp.net_mvc_4_4th_edition》的P358,电子版在www.it-ebooks.info   上可以下载到

 

 

在我们将静态文件的匹配放到后面以后,有两种方式来访问静态文件,第一种,为静态文件写路由第二种,用IgnoreRoute方法来访问静态问价

为磁盘上的文件写路由规则:《pro_asp.net_mvc_4_4th_edition》的P359

写这种路由要非常小心,因为这个路由是在最后才会被匹配,它很有可能在前面就已经被匹配掉了,因此这个做法不是首选

 

更好的解决方案是用 IgnoreRoute方法访问静态文件:

public static void RegisterRoutes(RouteCollection routes) {

routes.RouteExistingFiles = true;

routes.IgnoreRoute("Content/{filename}.html");                                             访问静态文件的路由

routes.MapRoute("DiskFile", "Content/StaticContent.html",

new {controller = "Customer",action = "List",});

            … ...

IgnoreRoute的语义是忽略路由,但它的作用并没有很好的体现他的语义,我们可以简单的把他看成是在为静态文件写路由,但是这个路由要放在其他路由的前面,这样就不会被其他的路由覆盖了