理解MVC路由配置(转)
在上一篇文章中,我简短的谈了一下MVC的底层运行机制,如果对MVC还不是很了解的朋友,可以作为入门的参照。接下来,我开始介绍关于URL路由的相关知识。URL路由不是MVC独有的,相反它是独立于MVC而单独存在的(在System.Web.Routing下)。因此,URL路由也能为传统的ASP.NET应用程序服务。我用一个简单的例子来解释路由,在我们的上一节的"ASP.NET MVC应用程序"中添加一个新的页面default.aspx,其后台代码如下:
protected void Page_Load(object sender, EventArgs e) { var originalPath = Request.Path; HttpContext.Current.RewritePath(Request.ApplicationPath, false); IHttpHandler handler = new MvcHttpHandler(); handler.ProcessRequest(HttpContext.Current); HttpContext.Current.RewritePath(originalPath, false); }
当执行请求页面default.aspx时,首先将请求的路径重写为"/",而该路径会匹配路由{controller}/{action}/{id},根据Global.asax路由配置,将映射为Home/Index/,从而输出Index.aspx的内容(而不是default.aspx的内容),不禁要问:为什么default.aspx在MVC应用程序中当做普通的ASP.NET页面,而不是将该请求转化为路由执行?是不是在MVC中就不能使用普通的ASP.NET页面呢?如果不能,当有一天我希望将我的普通站点转化为MVC站点时,是否还需要重新开发?带着这些疑问,我们进一步来探讨如何在MVC中支持原有的ASP.NET页面。在Global.asax中的Application_Start()方法中添加以下代码:
protected void Application_Start() { AreaRegistration.RegisterAllAreas(); RegisterRoutes(RouteTable.Routes); RouteTable.Routes.RouteExistingFiles = true; }
再次运行default.aspx会出现以前错误页面(找不到页面)。
刚才增加的代码:RouteTable.Routes.RouteExistingFiles = true(默认为false);表明MVC启用对现有Web页面的解析,此时尽管同样解析到路由{controller}/{action}/{id}上,但却找不到对应的控制器路由参数default.aspx,因而导致错误。接下来我们为它添加相关的路由设置,在Global.asax中添加以下代码:
//为default.aspx添加路由 routes.MapRoute( "Start", "default.aspx", new { controller = "Home", action = "Index", id = UrlParameter.Optional } );
删除或注释掉default.aspx.cs中的代码再次运行,会发现页面能正常解析。需要说明的是,URL路由的排列顺序非常关键,一旦找到第一个匹配的路由,将不会继续寻找剩下的路由了。是因为这里找到了匹配的路由Start,从而正确的映射到Home下的视图Index.aspx。为了更加深入理解路由解析的匹配规则,我们引入"路由匹配监控器"。添加引用"RouteDebug.dll",并在Global.asax中注册检测代码以分别检测没有启用和启用(依靠RouteExistingFiles属性)ASP.NET页面解析两种情况。
protected void Application_Start() { AreaRegistration.RegisterAllAreas(); RegisterRoutes(RouteTable.Routes); //RouteTable.Routes.RouteExistingFiles = true; RouteDebugger.RewriteRoutesForTesting(RouteTable.Routes); }
未启用(默认)Web页面解析的路由监控图
启用Web页面解析的路由监控图
从图中我们发现,当启用Web页面解析时,比未启用适多出一个路由项,这是因为此时是从Global.asax中去寻找匹配的路由项。过程大概是这样的:
首先会到路由表集合中寻找,如果找到匹配的路由定义则解析路由定义中的各个参数,依次获取参数映射的控制器/视图/参数信息,最后定位到指定控制器下的指定视图页面进行输出。相反,而过找不到对应的匹配路由则返回错误页面。
前面已提到过,URL路由的基本格式是: {controller}/{action}/{id},但也存在很多变体,总的来说,都会把不包含在{}中的部分当成常量来处理。如:blog/{action}/{author}的正确映射应该为:blog/show/miracle,再比如{report}/{year}/{month}/{day}映射为:sale/2012/5/25。这样就非常好理解页面具有的功能。
开发者一般都会通过Global.asax文件的Application_Start()来设置URL路由的定义,通过静态类RouteTable的Routes属性来设置路由。
public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); }