zoukankan      html  css  js  c++  java
  • 路由匹配的几点小结

    (1)控制器和动作方法的名字不区分大小写。

            public static void RegisterRoutes(RouteCollection routes)
            { 
                routes.MapRoute("MyRoute", "{controller}/{action}",
                    new { Controller = "Home", Action = "Index"});
            }

    对于测试

           [TestMethod]
            public void TestIncomingRoutes()
            {
                TestRouteMatch("~/", "home", "index");   //通过
            }
    TestRouteMatch("~/AAA/BBB", "aaa", "bbb");  //通过
    TestRouteMatch("~/AAA", "aaa", "Index");    //通过

    (2)可以使用静态URL片段,使路由只匹配地址中某一部分为固定值的URL

            public static void RegisterRoutes(RouteCollection routes)
            {
                routes.MapRoute("", "Public/{controller}/{action}",
                    new { Controller = "Home", Action = "Index" });
            }

    对于测试:

           [TestMethod]
            public void TestIncomingRoutes()
            {
                TestRouteMatch("~/Public/AAA/BBB", "AAA", "BBB");
                TestRouteMatch("~/Public/AAA", "AAA", "Index");
                TestRouteMatch("~/Public", "Home", "Index");
            }

    上面三种形式能通过测试,除此以外都不行。

    (3)使用静态URL片段时要注意路由顺序

            public static void RegisterRoutes(RouteCollection routes)
            {
                routes.MapRoute("MyRoute", "{controller}/{action}",
                    new { Controller = "Home", Action = "Index"});
                
    routes.MapRoute(
    "", "Public/{controller}/{action}", new { Controller = "Home", Action = "Index" }); }

    上面有两个路由,因此URL进来匹配的时候要注意顺序,从上往下,依次匹配。

    这个时候,对于如下URL

    "~/Public"

    就匹配不了第二个路由了,因为按照从上往下的顺序,在第一个路由匹配的时候就被拦截。

    对于测试:

            [TestMethod]
            public void TestIncomingRoutes()
            {
               TestRouteMatch("~/Public/AAA/BBB", "AAA", "BBB");  //通过,第一个路由不匹配3段式,漏下来匹配第二个路由
               TestRouteMatch("~/Public/AAA", "AAA", "Index");   //出错,两段式、一段式或"~/"都被第一个路由拦截。控制器应匹配为Public,动作为AAA
               TestRouteMatch("~/Public", "Home", "Index");      //出错,被第一个路由拦截。控制器应匹配为Public,动作为Index
            }

     (4)使用静态URL片段将指定的旧地址重新映射到新的控制器和动作方法上

            public static void RegisterRoutes(RouteCollection routes)
            {
                routes.MapRoute("ShopSchema2", "Shop/OldAction",  //注意没有大括号是静态URL
                    new { Controller = "Home", Action = "NewAction"});
    
                routes.MapRoute("ShopSchema", "Shop/{action}",
                    new { Controller = "Home", Action = "Index" });
            }

    对于测试:

            [TestMethod]
            public void TestIncomingRoutes()
            {
                TestRouteMatch("~/Shop/OldAction", "Home", "NewAction");
                TestRouteMatch("~/Shop", "Home", "Index");
                TestRouteMatch("~/Shop/AAA", "Home", "AAA");
                TestRouteFail("~/AAA/BBB");
            }           
    "~/Shop/OldAction" 将原来指定的这种URL重新映射到控制器Home、动作方法NewAction上。
    "~/Shop"第一个路由不匹配,漏下来,匹配第二个路由,控制器默认为Home,动作方法没有给出来,默认为Index。
    "~/Shop/AAA"第一个路由不匹配,匹配第二个路由,控制默认为Home,动作方法指定为AAA。
    "~/AAA/BBB"没有匹配的路由,只定义了两个路由,都必须由静态地址~/Shop开头。
     
    (5)URL上并不是只匹配controller和action变量,也可以定义自己的变量。
    例如:
            public static void RegisterRoutes(RouteCollection routes)
            {
                routes.MapRoute("MyRoute", "{controller}/{action}/{id}",
                    new { Controller = "Home", Action = "Index", id = "DefaultId" });
            }

    通过使用RouteData.Values属性,可以在一个动作方法中访问任何一个片段变量。

    下面添加HomeController类,编写Index动作方法:

            public ViewResult Index()
            {
                ViewBag.id = RouteData.Values["id"];
                return View();
            }

    这里使用RouteData.Values["id"]将URL里对应到路由中的自定义变量id的值读取出来,再使用ViewBag就可以把它传递给视图。编写/Views/Home文件夹中的Index.cshtml:

    @{
        ViewBag.Title = "Index";
    }
    
    <h2>ID: @ViewBag.id</h2>

    这样,对于:

    "~/"

    "~/Home"

    "~/Home/Index"

    "~/Home/Index/DefaultId"

    都是匹配到"~/Home/Index"页面,id变量的值都是DefaultId,在页面上显示出来的结果都为ID:DefaultId

    如果在浏览器上输入的地址是"~/Home/Index/AAA",则匹配到页面"~/Home/Index",id变量的值为AAA,页面显示出来的结果为ID:AAA

    在例如,保持路由定义不变,增加一个叫做CustomVariable的动作方法到HomeController类中:

           public ViewResult CustomVariable()
            {
                ViewBag.CustomVariable = RouteData.Values["id"];
                return View();
            }

    编写该动作方法对应的视图,即在/Views/Home文件夹中的CustomVariable.cshtml

    @{
        ViewBag.Title = "CustomVariable";
    }
    
    <h2>CustomVariable: @ViewBag.CustomVariable</h2>

    这样,对于:

    "~/Home/CustomVariable"

    "~/Home/CustomVariable/DefaultId"

    都是匹配到"~/Home/CustomVariable"页面,id变量的值都是DefaultId,在页面上显示出来的结果都为ID:DefaultId

    如果要对该路由定义:

            public static void RegisterRoutes(RouteCollection routes)
            {
                routes.MapRoute("MyRoute", "{controller}/{action}/{id}",
                    new { Controller = "Home", Action = "Index", id = "DefaultId" });
            }

    进行测试,则下面的测试可以通过:

            [TestMethod]
            public void TestIncomingRoutes()
            {
                TestRouteMatch("~/", "Home", "Index", new { id = "DefaultId"});
                TestRouteMatch("~/Customer", "Customer", "Index", new { id = "DefaultId" });
                TestRouteMatch("~/Customer/List", "Customer", "List", new { id = "DefaultId" });
                TestRouteMatch("~/Customer/List/All", "Customer", "List", new { id = "All" });
                TestRouteFail("~/Customer/List/All/Delete");       
            }           

    (6)使用跟自定义变量相同的名字来作为动作方法参数,以此来传递URL中对应到自定义变量的值

    例如,对于上面的例子,有路由定义:

            public static void RegisterRoutes(RouteCollection routes)
            {
                routes.MapRoute("MyRoute", "{controller}/{action}/{id}",
                    new { Controller = "Home", Action = "Index", id = "DefaultId" });
            }

    如果对HomeController类的Index动作方法:

            public ViewResult Index(string id) //跟路由定义中的自定义变量id同名
            {
                ViewBag.id = id;
                return View();
            }

    这里就不再使用RouteData.Values["id"]来将URL里对应到路由中的自定义变量id的值读取出来了。而是直接在动作方法上使用了跟路由定义中自定义变量id相同的名字作为参数,直接通过名字匹配后传递。

    假设,跟上面的例子一样编写该动作方法对应的视图,即在/Views/Home文件夹中的Index.cshtml

    @{
        ViewBag.Title = "Index";
    }
    
    <h2>ID: @ViewBag.id</h2>

    这样,对于:

    "~/"

    "~/Home"

    "~/Home/Index"

    "~/Home/Index/DefaultId"

    都是匹配到"~/Home/Index"页面,id变量的值都是DefaultId,在页面上显示出来的结果都为ID:DefaultId

    如果在浏览器上输入的地址是"~/Home/Index/AAA",则匹配到页面"~/Home/Index",id变量的值为AAA,页面显示出来的结果为ID:AAA

    注意,这里参数中的id,定义的是string类型,你也可以根据需要定义成int、DateTime等其他类型,根据名字id在URL模式上匹配后,会自动将URL中对应的自定义变量的值转换为参数中的指定类型。

    (7)定义可选的URL片段

    对于URL模式中的自定义变量,如果用户给出的访问地址URL中没有该自定义变量的值,即没有这个片段,但是我们又不想在定义路由的时候指定它的默认值,这时就可以用UrlParameter.Optional来指定可选URL片段。

    例如: 

            public static void RegisterRoutes(RouteCollection routes)
            {
                routes.MapRoute("MyRoute", "{controller}/{action}/{id}",
                    new { Controller = "Home", Action = "Index", id = UrlParameter.Optional });
            }

    在路由定义中,指定了URL模式中的自定义变量id是可选片段。

    如果有HomeController类的Index动作方法:

            public ViewResult Index(string id) //跟路由定义中的自定义变量id同名
            {
                ViewBag.id = id;
                return View();
            }

    跟上面的例子一样编写该动作方法对应的视图,即在/Views/Home文件夹中的Index.cshtml

    @{
        ViewBag.Title = "Index";
    }
    
    <h2>ID: @ViewBag.id</h2>

     那么,对于

    这样,对于:

    "~/"

    "~/Home"

    "~/Home/Index"

    都没有匹配的id的值,因为url中没有id对应的片段,因此url模式中的自定义变量id根本没有定义,那么,对于动作方法Index的参数也就找不到对应的的值。所以显示的结果都是:

    ID:

    但是,如果输入的url是"~/Home/Index/ABC"

    那么此时显示结果为

    ID:ABC

    这样做有一个好处,就是强制关注分离,使id的默认值不要设置在url的路由定义中。如果需要对id设置默认值,可以把它设置在函数参数中。

    例如,对于HomeController类的Index动作方法:

            public ViewResult Index(string id = "DefaultId") //跟路由定义中的自定义变量id同名
            {
                ViewBag.id = id;
                return View();
            }

    在测试含有UrlParameter.Optional的url片段时,需要注意的是,如果用户给出的url中未含有这个片段变量对应的值,那么,这个片段变量就不会被添加到RouteData.Values集合中。

    例如,对于路由定义: 

            public static void RegisterRoutes(RouteCollection routes)
            {
                routes.MapRoute("MyRoute", "{controller}/{action}/{id}",
                    new { Controller = "Home", Action = "Index", id = UrlParameter.Optional });
            }

    可以通过以下测试:

            [TestMethod]
            public void TestIncomingRoutes()
            {
                TestRouteMatch("~/", "Home", "Index);
                TestRouteMatch("~/Customer", "Customer", "Index");
                TestRouteMatch("~/Customer/List", "Customer", "List");
                TestRouteMatch("~/Customer/List/All", "Customer", "List", new { id = "All" });
                TestRouteFail("~/Customer/List/All/Delete");       
            }           

    (8)定义可变长路由,使用{*catchall}

    有路由定义:

            public static void RegisterRoutes(RouteCollection routes)
            {
                routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}",
                    new { Controller = "Home", Action = "Index", id = UrlParameter.Optional });
            }

    路由定义的后面使用了{*catchall},那么这个路由中的url模式匹配的片段数目没有上限。{*catchall}捕获的片段是以“片段/片段/片段”的形式表示的,不包括前面和后面的斜线“/”字符,程序员要自己负责处理这个字符串,自行拆分。

    可以通过以下测试:

            [TestMethod]
            public void TestIncomingRoutes()
            {
                TestRouteMatch("~/", "Home", "Index");
                TestRouteMatch("~/Customer", "Customer", "Index");
                TestRouteMatch("~/Customer/List", "Customer", "List");
                TestRouteMatch("~/Customer/List/All", "Customer", "List", new { id = "All" });
                TestRouteMatch("~/Customer/List/All/Delete", "Customer", "List", new { id = "All", catchall = "Delete" });   
                TestRouteMatch("~/Customer/List/All/Delete/Perm", "Customer", "List", new { id = "All", catchall = "Delete/Perm" });       
            }           

    (9)按命名空间区分控制器优先顺序

    假设在当前解决方案中有主项目11-3URLTestDemo,另在解决方案中通过file->add->new project,在项目类型上选择了Visula C#->web->asp.net mvc3 web application,添加了一个新项目叫做AdditionalController。假设在两个项目的Controllers中都有HomeController控制器。并且主项目添加了对AdditionalController项目的引用(注意顺序),那么当访问" ~/Home" 时,由于两个命名空间中都有HomeController,所以会产生冲突,出现错误。这时可以在主项目的路由定义中指定优先匹配的命名空间:

            public static void RegisterRoutes(RouteCollection routes)
            {
                routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}",
                    new { Controller = "Home", Action = "Index", id = UrlParameter.Optional },
                    new[] { "_11_3URLTestDemo.Controllers" });
            }

    -lyj

  • 相关阅读:
    Key&Main Window
    ObjectiveC Runtime IV 【使用隐藏的参数】
    JS中的变量作用域
    Git配置
    ObjectiveC Runtime II 【发送消息 vs 调用函数】
    GDB Vs. WinDbg Commands
    mcs51 串口通信 单片机发 pc收
    csharp截屏
    解决WIN7系统中系统文件的“拒绝访问”的方案
    在VC中创建DLL文件的方法步骤
  • 原文地址:https://www.cnblogs.com/brown-birds/p/3738040.html
Copyright © 2011-2022 走看看