MVC 路由规则
一、路由规则说明
先来看MVC中的默认路由的说明
"{controller}/{action}/{id}", // URL with parameters
对于Url /Home/Index/1 匹配结果是: controller : "Home" action : "Index" Id : "1"
对于Url /a.b/c-d/e-f
匹配结果是:
controller : "a.b"
action : "c-d"
Id : "e-f"
为了Asp.net MVC框架的正常运行,框架要求使用一些特定的参数名称{controller}和{action}。
假设我们想让所有的MVC请求都以site开头,那么路由我们可以改成这样
site/{controller}/{action}/{id}
假设想让所有的页面都以.aspx为后缀,则可以这样写
{controller}/{action}.aspx/{id}
现在来将Global.asax.cs的路由复制出来解释一下
public class MvcApplication : System.Web.HttpApplication { public static void RegisterGlobalFilters(GlobalFilterCollection filters) { filters.Add(new HandleErrorAttribute()); } public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( "Default", // 路由的名称 "{controller}/{action}/{id}", // 带参数的匹配规则 new { controller = "Home", action = "Index", id = UrlParameter.Optional } // 默认参数,即当不输入时间的处理方法 ); } protected void Application_Start() {
//这里还可以加一行
RouteTable.Routes.RouteExistingFiles = true; //如果设为true,这行表示,该网站所有的HTTP请求都会使用RegisterRoutes()方法中定义的网址里有规则一一进行比对,如果对比成功就会用Asp.net Mvc进行处理,若对比失败,再检查磁盘上的文件。默认是false的,因为Html文件,css,js文件等可以优先不经过路由直接显示。
AreaRegistration.RegisterAllAreas(); RegisterGlobalFilters(GlobalFilters.Filters);
//注册前面定义的路由,所有的Asp.net MVCRouting都在此定义,其中参数RouteTable.Routes是一个公开的静态对象,存储了所有的Routing规则集(RouteCollection类) RegisterRoutes(RouteTable.Routes); } }
1、IgnoreRoute 不理会的路由说白了就是用来定义不需要通过Routing处理的网址。
例如:http://localhost/Trace.axd
OK,该条路径匹配成功{resource}.axd比对到Trace.axd。而{*pathInfo}比对到空。因此匹配成功。匹配成功就怎么样呢?Ignore,不处理。也就是,上面那条Url是不会被Asp.net MVC处理的。
2、MapRoute() 最常用来定义Routing规则的辅助方法。用于定义一条路由。其中第一个参数是路由名称,第二个参数是Url以及参数,第三个是默认值。
3、我们之前看到个 * 号,它表示Catch-All。即不管什么乱七八糟的东西都匹配。没有就匹配空。
4、UrlParameter.Optional 指定可选参数的默认值,当不填写的时候,不会添加进参数字典。
二、自定义路由
routes.MapRoute( "Default", // 路由名称 "{controller}/{action}/{id}/{age}/{birthday}", // 带有参数的 URL new { controller = "Home", action = "Index", id = UrlParameter.Optional , age=18 ,birthday=new DateTime(1989,1,1) }, // 参数默认值 ); public ActionResult Index( string id , int age , DateTime birthday) { return View(); }
三、定义可变长度的参数的路由
routes.MapRoute( "Default", // 路由名称 "{controller}/{action}/{id}/{*catchall}", // 带有不定个数的参数的 URL new { controller = "Home", action = "Index", id=UrlParameter.Optional }, // 参数默认值 );
序号 | URL 示例 | 映射结果 |
0 | mydomain.com | controller=home,action=index |
1 | mydomain.com/Customer | controller=Customer,action=index |
2 | mydomain.com/Customer/List | controller=Customer,action=List |
3 | mydomain.com/Customer/List/All | controller=Customer,action=List,id=All |
4 | mydomain.com/Customer/List/All/Delete | controller=Customer,action=List,id=All,catchall=Delete |
5 | mydomain.com/Customer/List/All/Delete/Perm | controller=Customer,action=List,id=All,catchall=Delete/Perm |
四. 定义命名空间的优先级
根据以上内容我们已经知道,当URL匹配上一个路由之后,就会提取路由中的信息,然后进行进一步处理。假如现在我们的某个路由提取出了一个controller为Account ,并且我们的解决方案中有不只一个名为“AccountController”的类,由于路由并不知道要调用哪个controller ,这个时候就会出现错误。那么,如何解决这种问题呢?我们可以在注册路由的时候,指定某个路由有限查找controller 的命名空间,如下面的代码所示。
routes.MapRoute( "Default", // 路由名称 "{controller}/{action}/{id}", // 带有参数的 URL new { controller = "Home", action = "Index", id = UrlParameter.Optional }, // 参数默认值 new string[] { "MyNamespace.Controllers" } //指定优先命名空间 );
五、路由约束
routes.MapRoute( "Default", // 路由名称 "{controller}/{action}/{id}", // 带有参数的 URL new { controller = "Home", action = "Index", id = UrlParameter.Optional }, // 参数默认值 //设置匹配约束 new {controller = "^H.*" , action ="^Index$|^About&" , //必须要被正则表达式成功匹配,才使用该路由 httpMethod=new HttpMethodConstrain("Get") } //指定只使用Get方法的请求才会被匹配 );
public class UserConstrain : IRouteConstraint { public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection) { return true ; //你可以在这里做具体的操作 } } routes.MapRoute( "Default", // 路由名称 "{controller}/{action}/{id}", // 带有参数的 URL new { controller = "Home", action = "Index", id =UrlParameter.Optional }, // 参数默认值 new {controller = "^H.*" , action ="^Index$|^About&" , httpMethod=new HttpMethodConstrain("Get") , customConstrain= new UserConstrain () } , //设置匹配约束 new string[] { "MyNamespace.Controllers" } //指定优先命名空间 );