我们通过创建象下面这样一个ProductsController类来处理这些URL:
在把上面这个类加到我们的应用中后,asp.net mvc框架就会把进来的URL自动导向到我们的控制器上的适当的action方法来处理请求。
在今天的贴子里,我们将深入讨论这个URL映射是如何发生的,以及探讨我们可以在asp.net mvc框架中利用的更高级的路径选择(routing)场景。我还将示范你如何可以轻松地单元测试URL路径选择场景。
asp.net mvc 框架的URL路径选择系统都做些什么?
asp.net mvc 框架包括了一个很灵活的URL路径选择系统,它允许你在应用中定义URL映射规则。路径选择系统有2个主要目的:
把进来的URL映射到应用,并把它们做导向,这样,正确的Controller和Action方法执行来处理这些请求
构建可以用来回调Controllers/Actions的输出到客户端的URL(例如,表单提交, < a href=""> 链接, 和 AJAX 调用等等)
能够使用URL映射规则来同时处理进来的和输出的URL场景给应用代码添加了许多灵活性。这意味着,如果我们以后想改变应用的URL结构的话(譬如,把 /Products 改名为 /Catalog),我们可以修改应用层次的一套映射规则即可,而不需要改动控制器或视图模板中的任何代码。
默认的asp.net mvc URL路径选择规则
在默认情形下,当你使用Visual Studio用asp.net mvc Web Application模板来创建一个新项目时,它会往项目里添加一个asp.net Application类。这是在Global.asax后台代码中实现的:
asp.net Application类允许开发人员处理应用启动/中止以及全局性的错误处理的逻辑。
默认的asp.net mvc项目模板自动向该类添加一个Application_Start方法,在其中注册2条URL路径选择规则:
上面的***条路径选择规则表示,asp.net mvc框架在默认情形下,在决定用哪个Controller类来生成实例,调用哪个Action方法时(以及哪些需要传入的参数时),应该使用"[controller]/[action]/[id]"的格式把URL映射到控制器上。
这个默认的路径选择规则就是为什么***部分中我们的电子商务浏览例程中对URL /Products/Detail/3 的请求自动调用我们的ProductsController类的Detail方法,并且传入3作为id参数值的原因:
上面的第二条路径选择规则,是用来对我们应用的根URL"Default.aspx"做特例处理的(当处理一个应用的根URL的请求时,这个URL有时会被服务器代替"/"来传入)。这个规则确保对我们应用的根"/Default.aspx"或"/"的请求,都会由HomeController类(是在我们使用asp.net mvc Web Application项目模板生成一个新的应用时,由Visual Studio自动生成的控制器)里的Index() action方法处理。
理解Route实例
路径选择规则是通过向System.Web.mvc.RouteTable的Routes集合添加Route实例来注册的。
Route类定义了许多你可以用以配置映射规则的属性。你可以通过“传统的” .net 2.0属性赋值的方式来设置这些属性:
或者利用VS 2008的C#和VB编译器中的新的对象初始化器特性,更简洁地设置属性:
Route类的Url属性定义了应该用来评估一个路径选择规则是否适用于进来的特定请求的Url匹配规则。它还定义了URL应该如何分割成(tokenized)不同的参数。URL中可替换的参数,是通过 [参数名称] 的句法来定义的。就象在后文论及的那样,我们并不限制于一套固定的“熟知”参数名称,你可以在URL使用任何数目的任意参数。例如,我可以使用一个"/Blogs/[Username]/Archive/[Year]/[Month]/[Day]/[Title]"的URL规则把进来的一个博客贴子的URL进行分割,由mvc框架自动分析成UserName,Year,Month,Day 和 Title参数,并把它们传入我的控制器的action方法中。
Route类上的Defaults属性定义了一个默认值的字典,可以在进来的URL并不包含某个指定的参数值的情形下使用。例如,在上面的URL映射例子中,我们定义了2个默认URL参数值,一个是"[action]" ,另一个是 "[id]"。这意味着,如果应用收到的是 /Products/ 这个URL,在默认情形下,路径选择系统会默认使用“Index”作为ProductsController的action的名称来执行。同样地,如果指定了/Products/List/ ,那么就会使用null字符串作为"ID"参数的值。
Route类的RouteHandler属性定义了在URL被分割成参数,适当的路径选择规则被确定之后,应该用来处理请求的 IRouteHandler 实例。在上面的例子中,我们表示,我们想要使用System.Web.mvc.mvcRounteHandler类来处理我们配置好的URL。这个额外的步骤存在的原因是,我们想确保URL路径选择系统可以同时用于mvc和非mvc请求的情形。有这个IRouteHandler接口,意味着,我们也能够干净地用于非mvc的请求(例如标准的WebForms,Astoria REST支持等等)。
Route类还有一个Validation属性,在本文的稍后我们会做讨论。这个属性允许我们指定一个路径选择规则匹配需要满足的先决条件。例如,我们可以指定一个路径选择规则应该只适用于一个特定的HTTP动词(允许我们轻松地映射REST命令),或者我们可以对参数值使用正则表达式,来过滤一个路径选择规则是否匹配。
注:在asp.net mvc 框架的***个公开预览版中,Route类是不可以扩展的(它只是个数据类),在下一个预览版中,我们正在研究把它做成可扩展的,允许开发人员添加特定场景的路径类(譬如,一个RestRoute子类)来干净利索地添加新的语义和功能。
路径规则的评估
当一个进来的URL被asp.net mvc Web应用收到时, asp.net mvc 框架会对RouteTable.Routes集合中的路径选择规则进行评估,以决定适当的Controller来处理该请求。
asp.net mvc 框架是按RouteTable规则注册的次序做评估来选择使用哪个Controller的。将进来的URL对每条Route规则做检测,看它是否匹配,如果一个Route规则匹配的话,那么该规则(以及相关联的RouteHandler)将被用来处理进来的请求(所有后面的规则都略过不计)。这意味着你一般要按“最特殊到最不特殊(most specific to least specific,从特殊到一般)”的次序来组织你的路径选择规则。
【编辑推荐】