ASP.NET MVC路由——没人告诉你的事

2018年1月24日

路由是URL到处理该URL的逻辑的映射。在经典ASP.NET窗体网站中,路由并不那么令人感兴趣,因为经典ASP.NET窗体网站的URL直接映射到aspx文件,如https://gqqnbig.me/default.aspx就由default.aspx执行。

ASP.NET MVC的主要特性之一就是URL与具体的处理程序解耦了,处理程序称为Controller控制器,即MVC的C。不要以为URL不重要,用户用URL来探索站点结构。例如本文的URL是https://gqqnbig.me/2018/01/24/asp-net-mvc路由-没人告诉你的事/,用户期望删除后面部分,使用https://gqqnbig.me/2018/01/24/到达日度归档。另一方面,结构化的URL有助于搜索引擎优化。

既然路由是URL到处理控制器的映射,我们需要URL和控制器两者来定义路由。一个路由器对应一个路由,如default -> DefaultController,这种方式效率太低了,所以.NET Framework使用通配符和占位符的方法定义路由。

在Visual Studio中新建.NET Framework ASP.NET MVC应用程序,Global.asax.cs里有

public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);
    }
}

其中RouteConfig.RegisterRoutes(RouteTable.Routes)要求在应用程序启动时注册路由表,该方法的方法体为

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");//(1)

    routes.MapRoute( //(2)
        name: "Default",
        url: "{controller}/{action}/{id}",
        defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
    );
}
代码1

对于(1)的作用,所有文章要么没解释,要么用同一句话解释[1][2][3]:不对.axd文件进行路由。但读者仍然不知道{resource}、“*”、斜杠的意思。这个就是URL模式。许多人,甚至是微软MVP[4],都不清楚它的具体用法。下面我们来研究它。

URL模式

路由需要定义URL模式,URL模式包含常量值、URI片段分隔符(斜杠)和占位符。

占位符由成对的大括号标记,如{resource}{id}。两个占位符之间必须有常量值或斜杠,如{language}{country}/{action}不是合法的URL模式,而{language}-{country}/{action}是。占位符类似于变量,其名字是任意的,只要变量调用方调用正确的名字。下列URL模式具有完全相同的功能。

routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.IgnoreRoute("{x}.axd/{*y}");
routes.IgnoreRoute("{hello}.axd/{*word}");

URI片段分隔符在Uri.Segments 属性有介绍,用于把URI(URL的超类)划分成不包括斜杠的片段。由定义可知,第一个URI片段永远为/

URL URI片段
http://www.contoso.com/Chapters/Chapter1/Sections/Section1.htm#page1?answer=NO
  1. /
  2. Chapters
  3. Chapter1
  4. Sections
  5. Section1.htm
https://www.google.com
  1. /
https://www.google.com/
  1. /

此外,URI片段分隔符不能连续出现,否则将抛出异常。

在路由过程中,不是URL与URL模式直接匹配,而是URL片段与URL模式片段匹配。

占位符中的星号(*)将该占位符标识为变长占位符Catch-all placeholder,全部捕捉占位符),变长意思是允许匹配多个或零个URI片段。使用{resource}.axd/{*pathInfo}对下列URL进行匹配,占位符的捕获情况如下。

URL URI片段
https://gqqnbig.me/WebResource.axd?d=PhPk80h_UWEcbheb&t=632573240669964903 resource=WebResource
pathInfo=空字符串
https://gqqnbig.me/ScriptResource.axd/underscore/1.0/ resource=”ScriptResource”
pathInfo=”underscore/1.0/”
https://gqqnbig.me/ScriptResource.axd/underscore/1.0 resource=”ScriptResource”
pathInfo=”underscore/1.0/”
https://gqqnbig.me/aspnet/ScriptResource.axd/underscore/1.0 不匹配

params可变参数关键字一样,ASP.NET仅允许最后一个占位符为变长占位符。

代码1的(2)部分指定如何从URL映射到控制器。如果URL不足三段,则余下的占位符变量值取默认值。下标显示了多种情况下占位符的取值情况。

URL 占位符取值
https://gqqnbig.me/Home/About controller=”Home”
action=”About”
id=UrlParameter.Optional (取默认值)
https://gqqnbig.me/Home controller=”Home”
action=”Index” (取默认值)
id=UrlParameter.Optional
https://gqqnbig.me/ controller=”Home” (取默认值)
action=”Index” (取默认值)
id=UrlParameter.Optional
https://gqqnbig.me/Czecho/Slovakia/Republic controller=”Czecho”
action=”Slovakia”
id=”Republic”
https://gqqnbig.me/United/States/Of/America 不匹配

这里不能随便命名占位符,因为{controller}{action}是特殊占位符,分别表示控制器的类名和方法名。控制器方法如果想接受参数,参数名必须与其他的URL占位符相匹配。

参考资料

  • Peter Johnson. MVC's IgnoreRoute syntax. . 2010-11-11 [2018-01-23].
  • [CiteBook author=”Dino Esposito” title=”ASP.NET MVC 5编程实战” edition=”第三版” publisher=”清华大学出版社” isbn=”978-7-302-39480-8″]

参考资料

  1. huangenai. asp.net MVC 5 路由 Routing. . 2017-07-26 [2018-01-23].
  2. Alan_beijing. 【ASP.NET MVC系列】浅谈ASP.NET MVC 路由. . 2017-06-29 [2018-01-23].
  3. Amir Popovich. Can someone explain what routes.IgnoreRoute(“{resource}.axd/{*pathInfo}”); is need for?. . 2014-04-25 [2018-01-24].
  4. Edi Wang. ASP.NET MVC3和传统WebForm共存时,Chart控件无法显示的解决办法. . 2012-07-01 [2018-06-08].