首页 > 代码库 > 约束路由

约束路由

1、用正则表达式约束路由

有工程11-3URLTestDemo,如在Global.asax中有如下路由定义:

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

这里的new[] { "_11_3URLTestDemo.Controllers" }表示优先匹配_11_3URLTestDemo.Controllers命名空间中的控制器,这是为了避免在不同的命名空间中有同名的控制器时出现命名冲突,通过此种方式可以指定匹配的优先顺序。

这里我们关注的是正则表达式来约束路由。约束被表示成一个匿名类型,该类型的属性对应到想要进行约束的片段变量名,例如这里就是Controller,表明后面的正则表达式"^H.*"是用来约束url中对应controller变量的值的。Controller="^H.*"表示只匹配Controller变量的值以"H"打头的url,url本身不区分大小写,这里的H也不区分大小写。

假设有两个控制器,一个是HomeController,另一个是AccountController,两个控制器里都定义有Index方法。那么对于上面的约束,如有url:

~/home 可以匹配

对于url:

~/Account 则不匹配。

=====

需要注意,这里Controller变量的默认值问题。默认值是在约束检查之前运用的。因此,如果请求的url是根目录"~/",Controller的默认值"Home"会被运用,然后才检查约束。但需要注意的是,这并不意味着不再做约束检查,事实上,检查仍然要做,如果通不过检查,url也不会匹配。

例如,将路由定义作如下修改,把Controller的默认值改为了Account:

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

这个时候如果请求的url是根目录"~/",就无法匹配。因为默认值Account不能通过约束检查——第一个字母必须是H(不分大小写)。

 

2、约束到指定值

例如:

        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[] { "_11_3URLTestDemo.Controllers" });
        }

这里定义的路由匹配的url被约束为:Controller变量的值要以H(不分大小写)字母开头,而且Action变量必须是Index或About。

"~/Home/Index"

"~/Home/About"

这两个url可以匹配。

用这种方式可以限制到比较精确的url。

3、约束使用HTTP方法的路由

例如:

        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")},
                new[] { "_11_3URLTestDemo.Controllers" });
        }

这里定义的路由就限定了只能匹配使用GET方法进行请求的url。

注意这里的名字httpMethod是自己指定的,只要给它赋值为一个HttpMethodConstraint类的实例就可以了。

上面的例子限定了只能使用GET方法,也可以很容易的添加另外的方法:

httpMethod = new HttpMethodConstraint("GET", "POST")

 

4、单元测试:路由约束

测试路由约束时,最好对所要匹配的url和试图排除的url都进行测试。

例如:

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

            TestRouteMatch("~/Home/About", "Home", "About");
            TestRouteMatch("~/Home/About/MyId", "Home", "About", new { id="MyId"});
            TestRouteMatch("~/Home/About/MyId/More/Segments", "Home", "About", 
                new { id = "MyId", catchall="More/Segments" });
            
            TestRouteFail("~/Home/OtherAction");
            TestRouteFail("~/Account/Index");
            TestRouteFail("~/Account/About"); 
        }           

也可以测试HTTP方法。

重载TestRouteFail,增添一个参数httpMehod

        private void TestRouteFail(string url, string httpMethod)
        {
            //布置
            RouteCollection routes = new RouteCollection();
            MvcApplication.RegisterRoutes(routes);

            //动作
            RouteData result = routes.GetRouteData(CreateHttpContext(url, httpMethod));

            //断言
            Assert.IsTrue(result == null || result.Route == null);
        }

下面就可以测试对HTTP方法的约束:

        [TestMethod]
        public void RegisterRoutesTest()
        {
            TestRouteMatch("~/", "Home", "Index", null, "get");
            TestRouteFail("~/", "POST");
        }