最近我们开启了一个新的ASP.NET CodePlex 项目,我们将用它来提供将要发布的ASP.NET特性的预览(以及可编译的源代码)。
上个月,我们用它发布了ASP.NET MVC源码的第一个投放,这个投放包括了我们在MIX上发布的ASP.NET MVC第二个预览版的源码,以及允许你修补和编译的Visual Studio项目文件。
几小时前,我们在该网站上发布了ASP.NET MVC源码的一个更新版。这个源码更新版 不是正式的ASP.NET MVC新的预览版,而是一个过渡性的版本,旨在对源码树的当前状态提供一个样本。我们将在几个星期内完成一些工作后发布正式的“ASP.NET MVC第三个预览版”,这些工作包括新的特性以及对现有的特性的加工,更好的VS工具集成,VS Express版本的支持,以及文档等。如果你想要一个毫无麻烦的ASP.NET MVC安装版,带有文档以及完整的工具支持的话,你也许要等到这个正式的预览版出来后再说。如果你想要有机会看一下早期的“预览版的预览”,马上有机会开始使用一些特性,并且对它们提供反馈的话,那么今天的源码更新版值得一看。
这个ASP.NET MVC源码更新版中的一些改进
这个星期的更新版(你可以在这里下载)包括了对ASP.NET MVC的若干改进。这些改进包括:
除了发布ASP.NET MVC框架的源码外,我们还发布了我们用来测试该框架的单元测试的源码,这些测试是使用MSTest以及开源的Moq mocking 框架实现的。内含一个单元测试的VS 2008项目文件,方便你在本地的VS 2008 IDE中编译和运行。
对测试Controller类的的显着简化了的支持,你现在可以不用mock任何对象就可以单元测试常见的Controller场景(详情见下文)。
URL路径选择系统的几个新特性和可用性方面的改进(详情见下文)。
创建新的ASP.NET MVC项目
在下载MVC源码,在本地编译后,你可以建造你自己的ASP.NET MVC程序集,或者你也可以下载一个VS模板包,得到这些程序集的预制版本,其中包括一个 Visual Studio的项目模板,你可以用它来快速建造使用了最新代码的新ASP.NET MVC项目
在安装ASP.NET MVC源码更新 .VSI 模板后,一个新的“ASP.NET MVC应用”项目模板会出现在你的“新项目”对话框的“我的模板”部分:
在你使用这个更新的ASP.NET MVC项目模板创建一个新项目时,在默认情形下,你将得到一个如下图所示的项目:
这个项目方案在“Controllers”目录下包含一个Controller(“HomeController”),在“ViewsHome”子目录下包含2个视图模板(“About”和“Index”)。 2个视图模板都基于网站的共同母版页(“Site.master”),这些文件的样式定义于“Content”目录下的“Site.css”文件中。
在你运行应用时,内置的web服务器会自动启动,你将看到网站的首页内容:
点击“About us”条,就会显示“About”内容:
项目中的“HomeController”类负责处理上面2个URL,有下述2个action方法:
默认的“Site.master”模板会在ViewData集合中寻找一个“Title”值,用它来显示HTML页面的<title>元素,默认的“Index”视图模板会找一个“Message”,用它来显示首页的欢迎消息,很明显,你可以进去定制这些文件。
这个ASP.NET MVC投放版的Controller变动
如果你在认真阅读上面的代码的话,你也许注意到了用这个新的ASP.NET MVC源码更新版默认实现的Controller类中的几个变动。
在ASP.NET MVC第二个预览版中,上面的HomeController action方法是象这样实现的:
Controller中的Action方法现在默认返回“ActionResult”对象(而不是void),这个ActionResult对象表示action方法的结果,如显示一个视图,重定向的URL,另一个要执行的action/路径,等等。
Controller基类中的RenderView(),RedirectToAction(),和 Redirect() 辅助方法现在返回强类型的ActionResult对象(你可以对其做进一步的操作或从action方法中返回)。
RenderView()辅助方法现在可以不用显式传人要显示的视图模板名称就可以调用,如果你省略模板名字的话,在默认情形下,RenderView()方法将使用action方法的名字作为要显示的视图模板的名称。所以,在“About()” action方法中,不用参数调用“RenderView()”现在跟显式调用“RenderView('About')”是一样的。
很容易将用第二个预览版建造的现有Controller类更新到使用这个新的模式(只要将void改成ActionResult,然后在任何RenderView或RedirectToAction方法调用前加一个return语句就可以了。
从Action方法中返回ActionResult对象
那么,为什么将Controller action方法改成默认返回ActionResult,而不是返回void呢?有几个流行的Web-MVC框架使用同样的返回对象的方式(包括Django, Tapestry等),我们发现它给ASP.NET MVC带来几个好处:
它促成对Controller的更干净,更方便的单元测试支持。你不再需要对Response对象或ViewEngine对象的方法进行mock就可以单元测试action方法的回复行为,你只要简单地在单元测试中使用从Action方法返回的ActionResult进行assert就可以了(见下一部分)。
它可以在那些取决于某种条件会有2不同结果的场景中,使得Controller逻辑流的意图更清晰,更明确(例如,如果条件A为真,就重新定向,否则显示一个视图模板)。这可以使得不简单的控制器action方法的代码易读,好懂些。
它能促成一些非常棒的组合场景,在这些场景中,FilterActionAttribute可以将action方法的结果,在执行之前进行修改、转换。例如,ProductCatalog控制器的“Browse”方法也许会返回一个RenderActionResult,表示它要显示产品的“List”视图,在控制器类上声明的FilterActionAttribute然后就有机会取决于客户端能接受的MIME类型,将要显示的特定“List”视图模板定制为List-html.aspx或List-xml.aspx。多个FilterActionAttribute还可以链在一起,把结果从一个传给另一个。
它还为开发人员(包括我们自己)提供了很好的扩展性机制,以在将来添加额外的功能。可以通过从ActionResult基类继承,覆盖其中的“ExecuteResult”方法来轻易地创建新的ActionResult 类型。例如,可以很轻易地创建一个“RenderFile()”辅助方法,编写action方法的开发人员可以调用它来返回新的“FileActionResult”对象。
这个过渡性预览版的一个目标是给大家一个机会把玩一下这个新方法,用它来建造现实的应用,从中学习一下。
我们还将发布一个可为你所用的另外的Controller基类的样例,如果你还是喜欢以前的“void” action返回值方式的话。但在这个源码更新版中,我们故意没有包括这个另外的Controller基类,因为我们想要鼓励大家尝试一下“ActionResult”返回方式,给我们一些用它来建造应用的反馈。
如何单元测试Controller Action方法
我在上面提到,新的ActionResult方法可以极大地简化对控制器的单元测试,且避免在常见场景中使用mocking,让我们通过一个实战例子来示范一下。
考虑下面这个简单的NumberController类:
对我们的“IsEvenNumber” action方法编写单元测试非常容易,多亏新的ActionResult方法。
下面是一个单元测试例子,核实在提供负数时,正确的Http重新定向发生了(例如,/Number/IsEvenNumber/-1):
注意上面,我们不用mock任何对象就可以测试我们的action方法。我们只是生成了一个NumberController类的实例,直接调用action方法(传人一个负数),然后将返回值赋给一个本地“result”变量。上面我用了C#的“as type”语法,将“result”变量转换成一个强类型的“HttpRedirectResult”类型。
C#的 “as” 关键词的一个好处是,如果转换失败的话,它会赋null值,而不是抛出异常(例如,如果action方法返回的是个RenderViewResult)。这意味着,我可以轻松地在我的测试中加一个assertion检查,核实结果不是null,以核实Http重新定向确实发生了。然后我可以加第二个assertion检查,以核实指定了正确的重新定向URL。
测试非零数字的场景也很容易,要做的话,我们将创建2个测试方法,一个测试偶数,另一个测试奇数。在这2个测试中,我们将断言返回了RenderViewResult,然后核实在与视图相关的ViewData中传进了正确的“Message”字符串:
然后我们可以在VS 2008中右击我们的NumberControllerTest类,选择“运行测试”菜单项:
这会在内存中执行我们的三个单元测试(不需要web服务器),报告我们的NumberController.IsEvenNumber() action方法是否执行了正确的行为:
注: 在这个星期的源码投放中,你还需要使用mocking来测试Controller的TempData属性。我们的计划是在几个星期后的ASP.NET MVC第三个预览版中不再需要mocking就可以测试这个属性。
MapRoute辅助方法
ASP.NET MVC应用中的URL路径选择规则一般是在Global.asax类的“RegisterRoutes”方法中声明的。
在ASP.NET MVC第一个预览版和第二个预览版中, 路径是通过直接生成一个Route对象,将其连接到一个MvcRouteHandler类,然后设置其上的适当属性来声明路径规则,再加到routes集合的:
上面的代码以后还会继续工作,但是,你现在还可以利用新的“MapRoute”辅助方法,它提供了极其简单的句法,但能做同样的事。下面是在你创建一个新的ASP.NET MVC项目时,默认配置的基于约定的URL路径(代替上面的代码):
MapRoute()辅助方法是重载了的,可以接受2,3,或4个参数(路径名字,URL句法,URL默认参数,URL参数正则表达式约束)。
你可以调用MapRoute()多次, 在系统中注册多个具名的路径。例如,除了默认的约定规则外,我们可以象下面一样加一个名为“Products-Browse”的路径规则:
然后我们可以在Controllers和Views中明确地引用这个“Products-Browse”规则,如果我们要生成一个针对它的URL的话。例如,我们可以在视图模板中使用象下面这样的代码,使用Html.RouteLink这个视图辅助方法,来表示我们要链接到“Products-Browse”路径上,同时给它传一个“Food”分类参数:
这个视图辅助方法然后就会访问路径选择系统,输出象下面这样的适当的HTML超链接URL(注意它是如何自动地使用路径规则将分类参数置换到URL中去的):
注: 在这个星期的源码投放中,你需要向Html.RouteLink()辅助方法中传人控制器和action参数(除了分类参数外)来生成正确的路径URL。几个星期后的ASP.NET MVC第三个预览版将不再要求这样,而是允许你象我上面写的Html.RouteLink调用那样,来确定路径。
其他URL路径映射功能
这个星期的MVC源码投放还支持一堆新的URL路径映射功能,你现在可以在你的路径规则中包含"-", ".", ";" 或任何其他你想要作为URL的一部分的字符。
例如,使用"-" 分割符你现在可以使用象下面这样的规则从你的URL中分别分析出language和locale值:
这会调用时,将合适的"language", "locale", 和 "category"参数传人ProductsController.Browse action方法中:
URL路径规则 | URL例子 | 传给Action方法的参数 |
{language}-{locale}/products/browse/{category} | /en-us/products/browse/food | language=en, locale=us, category=food |
/en-uk/products/browse/food | language=en, locale=uk, category=food |
或者你可以使用URL后面的 "." 文件扩展类型来决定是要以XML还是HTML格式来显示内容:
这会在调用时将"category" 和 "format"参数传给ProductsController.Browse Action方法:
URL路径规则 | URL例子 | 传给Action方法的参数 |
products/browse/{category}.{format} | /products/browse/food.xml | category=food, format=xml |
/products/browse/food.html | category=food, format=html |
ASP.NET MVC第二个预览版引进了通配符路径规则,例如,你可以在一个规则中表示,把所有剩下的URI内容作为一个具名的参数传给一个action方法:
这会在调用时,将一个"contentUrl" 参数传给WikiController.DisplayPage action方法:
URL路径规则 | URL例子 | 传给Action方法的参数 |
Wiki/Pages/{*contentUrl} | /Wiki/Pages/People/Scott | contentUrl="People/Scott" |
/Wiki/Pages/Countries/UK | contentUrl="Countries/UK" |
这些通配符路径在本星期发布的预览更新版中还会照常工作,在你建造博客,维基,CMS,或其他基于内容的系统时,这些规则非常值得一看。
注意,除了在ASP.NET MVC场景中使用新的路径系统外,我们现在还将在ASP.NET动态数据(使用了ASP.NET Web Forms)中使用同样的路径系统。
结语
希望上面的内容对本星期的ASP.NET MVC源码更新版中的一些新功能和变动提供了简短的说明。
你现在可以下载,如果你想要马上开始使用它的话。或者,你也可以等上几个星期,等正式的 ASP.NET MVC第三个预览版发布,这正式的版本将拥有更多的功能(也会融入大家对本星期的版本的反馈),提供更加无缝的安装程序,提供很好的VS集成,提供更新的文档。
对本星期的ASP.NET MVC更新版有什么问题的话,一定要去www.asp.net上的ASP.NET MVC论坛询问。
希望本文对你有所帮助