jasonoiu 2009-06-01
51CTO编辑推荐:《ASP.NET MVC 视频教程》
其一,这种分割,虽然比通常情况要求投入稍多的工作,但有助于保持应用程序的可维护性。另一个优点是它能够更好地对你的代码进行单元测试。framework 框架(以及它的 Visual Studio 内置包)可帮助你创建单元测试结构,例如,以从控制器的方式创建;而你的任务就是编写实际的测试代码。ASP.NET MVC 1.0 刚刚推出才三个月,因此要在行业内获得较好的应用还需要时间。不过,无论你使用传统的 WebForm 表单技术还是 ASP.NET MVC,某些要求仍将是不变的:你需要对用户界面进行测试、本地化以及进行细节调整。在本文中,我们将学习使用不同的方式对 ASP.NET MVC 应用程序进行单元测试,如何对多种语言进行本地化,以及在最后,学习如何在用户界面中添加 AJAX 触控,其中的用户界面使用 MVC 项目中的视图实现。
从本地化开始
对于网页应用程序,创建多种语言的用户界面并不是什么新问题。事实上,ASP.NET 从最早的版本开始就内置了对本地化的支持。例如,你可能使用用户局部或全局资源,并在控制和/或 .aspx 文件中使用 %$ % 构造进行相关的引用。ASP.NET MVC 应用程序中的视图通常是常规的 .aspx 文件,因此你可以使用与 MVC 应用程序中完全相同的方法(参见图 1)。
图 1. ASP.NET MVC 应用程序的缺省外观和布局。
除了这种传统的本地化方法,你还可以将这种逻辑添加到控制器类中。由于使用 %$ % 是一种有点枯燥的方法,你可以使用该构造,根据当前所用的语言,从控制器返回不同的视图。这是非常有用的,尤其,当不同语言版本的视图不必保持一致时。例如,视图的英文版比法语版具有更好的扩张性。
下面,我们看看实际操作中的这两种选择。假设你开始创建了一个简单的 ASP.NET MVC 应用程序,尚未进行任何定制。Visual Studio 缺省创建的应用程序结构包含 Home 和 Account 控制器。例如,如果需要对 Home/About 文本进行本地化,你可以按照以下方式进行操作。
首先,你可以使用传统的本地化方法:使用资源。例如,要使用全局资源,你需要将 App_GlobalResources 文件夹添加到你的解决方案中。在 Visual Studio 的解决方案管理器(Solution Explorer)中右键点击项目节点,选择 Add/Add ASP.NET Folder/App_GlobalResources 。这样就可以创建所需的文件夹。
下一步是添加资源文件。在解决方案管理器,右键点击新创建的文件夹,在弹出菜单中选择 Add/New Item。这将打开 Add New Item 对话框,从中选择资源文件(Resources File )图标。为资源文件命名之后,单击 OK,Visual Studio 将会将它添加到你的项目中。然后,你可以在显示的表格中键入资源字符串(图 2)。使用资源时,对于在应用程序中进行本地化的每个字符串,你需要指定一个标识符。
图 2. 在 ASP.NET MVC 应用程序中使用资源字符串进行本地化。
在开始对应用程序进行本地户之前,指定容易识别的字符串是一个好习惯,因为在试图页面中引用字符串时,你需要这些标识符。另外需记住,许多字符串对于每个页面都是唯一的,因此可能存在多个字符串,你可以在多个视图中使用它们,有时需要标识符名称能够反应这种情况。引用本地化的字符串很简单:你可以使用 ASP.NET 2.0 中引入的 %$ Resources %构造。例如,在 MyResources.resx 资源文件中有一个名为 HelloWorldText 的字符串,下面这段 .aspx 文件中代码,可以根据用户的首选语言,正确地转换为本地化字符串:
asp:Literal ID="Literal1" runat="server" Text="%$ Resources: MyResources, HelloWorldText %" / |
关于 ASP.NET MVC 查找正确的本地化版本,framework 框架使用专业的文件命名规则。MyResources.resx 资源文件包含相关语言的字符串,该语言被认为是该应用程序的初始语言。如果用户的浏览器未指定语言,或者你没有在代码中指定一个语种,那么将使用初始语言字符串。不过,如果用户选择的语言为德语 那么该语言的首字母所写“de”将添加到资源文件名称后:MyResources.de.resx。其他语言也一样,例如 MyResources.es.resx 文件中包含西班牙语字符串。对于本地化,你可以还想要在 .aspx 文件的 @Page 标签中添加专用指令。比如,想要自动检测用户浏览器语言设置,你可以在该标签(指定缺省语言的冒号之后)中添加 UICulture="auto" 属性:
%@ Page ... UICulture="auto:en-US" % |
对简单视图进行本地化的另外一种选择是根据用户的语言返回不同的视图。需要在控制器中包含一些逻辑算法,不过代码很容易编写。例如,你可以使用以下的逻辑:
public ActionResult Localized() { if (Request.UserLanguages.Length 0) { string lang = Request.UserLanguages[0]; if (lang.ToUpper().StartsWith("DE")) { return View("Localized-DE"); } else return View("Localized-EN"); } else return View("Localized-EN"); } |
你也可以将这些代码封装在(应用)方法中。如果需要结合使用这两种方式,那好消息是:你可以自由地进行组合和匹配。情况正是如此,ASP.NET MVC 应用程序的本地化不应受到目前可用技术的限制。
MVC 应用程序的单元测试
ASP.NET MVC 应用程序的优点之一是能够更好地对你的代码进行单元测试。虽然也可以对常规的 ASP.NET WebForm 应用程序进行测试,但通常认为它较为麻烦,因为应用程序模型将用户界面、数据访问和逻辑算法都混合到同一代码文件和类之中了。相反,ASP.NET MVC 应用程序结构可构建天然的边界,便于进行单元测试。
通常,控制器类是最好的测试起始之处。控制器方法无需用户界面,并且因此没有函数的交互使用,所以它们是很好的测试对象。在开始创建一个 ASP.NET MVC 项目时,Visual Studio 会询问是否在解决方案添加单元测试项目。如果你选择添加,那么解决方案的显示将与图 3 所示类似:
图 3. ASP.NET MVC 应用程序缺省的解决方案结构。
缺省模块建议为每个控制器方法创建一个单元测试,但对于测试数量并没有限制。如果安装了 Visual Studio 2008 Professiona,可以使用 Solution 菜单命令中的 Test/Run/All Tests 运行解决方案中的所有可用测试(图 4)。
图 4. Visual Studio 中的单元测试结果。
ASP.NET MVC 的测试代码编写与其他 .NET 应用程序类似。你可以使用 Assert 类(在 Microsoft.VisualStudio.TestTools.UnitTesting 名称空间内定义),以使 Visual Studio 获得测试结果。例如,你的测试可能检查控制器方法 Customers是否在 ViewData 对象中返回正确的数据:
[TestMethod] public void Customers() { HomeController controller = new HomeController(); ViewResult result = controller.Customers() as ViewResult; ViewDataDictionary viewData = result.ViewData; string tableName = "Customers"; Assert.AreEqual(tableName, viewData["tableName"]); } |
如果测试运行很快,即使运行几百个测试也会很顺利。不过,由于许多 ASP.NET MVC 应用程序使用 SQL 数据库,对这些访问进程进行测试可能需要一些时间。当然,你还应该对数据访问类进行测试(也许还有模型),但通常,在测试进程中使用内存静态数据模拟数据访问更为方便。
其中一种实施方法是创建数据访问接口,然后,通过让一个类进行真正的数据访问,而另一个仅模拟这种访问。这个模拟类可以从内存中返回静态数据而不是访问真正 的数据库。利用这两个布置,你可以在应用程序中使用真实数据库访问,而在单元测试中使用模拟数据库访问。对于控制器测试,这种模拟式的数据访问通常已足够,而且可以更快地进行测试。
事实上,这种模拟类通常称为模拟对象(mock ojbect)。模拟对象可以作为真实类的替代使用,这有助于编写单元测试。在数据库访中,这种模拟对象是很有用的,但对于其他一些情况,也是如此。对于数据库访问,通常它有助于编写你自己的模拟对象,但对于其他测试任务,如要求验证,你可能需要使用预制的模拟对象库。
对于 .NET,有多个库可供使用,三个常用的是 EasyMock.NET、Moq 和 Rhino Mocks。这些都是开源的解决方案,相关网址请参阅下文中的链接部分。模拟的使用与库相关,但通常他们需要你初始化 framework 框架,之后你就可以使用模拟对象替换真实对象了。
例如,你的视图是保护型的,因此,只有通过授权的用户可以访问(使用控制器中的 Authorize 属性指定),那么,为了成功地运行测试,单元测试需要构造合适的验证对象。尤其验证对象是 User 和 Identity 对象时。以下是一个示例,使用 Moq 库创建模拟对象以帮助测试需要验证的视图:
using Moq; using System.Web; using System.Security.Principal; ... HomeController controller = new HomeController(); var context = new MockControllerContext(); var user = new MockIPrincipal(); var identity = new MockIIdentity(); context.Setup( ctx = ctx.HttpContext.User).Returns( user.Object); user.Setup(ctx = ctx.Identity).Returns( identity.Object); identity.Setup( id = id.IsAuthenticated).Returns(true); identity.Setup( id = id.Name).Returns("John Doe"); controller.ControllerContext = context.Object; |
Moq 库非常依赖 C# lambda 表达式,为单元测试提供了新式触控。如果你多多少少接触过 lambda 表达式,那 framework 框架对你来说是非常容易学习。
请注意,如果你下载的测试 framework 框架为二进制文件,可能会遇到安全问题。如果你简单地将 DLL 文件复制到解决方案文件中,然后通过引用来使用 framework,就会出现这种问题。对于这种情况,在运行测试时,Visual Studio 会报告“Not Executed”(未执行)。如果错误详情中出现以下类似文字:Test Run deployment issue: The location of the file or directory 'library.dll' is not trusted(测试运行故障:文件或目录 library.dll 的位置未经验证),那就是发生了安全问题。解决这种安全问题的最简单方式是,在 Windows 资源管理器中,打开 DLL 文件的属性窗口(alt + 双击),然后单击 Unblock(解锁)按钮。另外一种方法是利用 Caspol 程序对组件添加完全信任。
在应用程序总添加 AJAX 触控
虽然 XHTML 和 CSS 中的最新功能能够带你走得更远,但在浏览器中使用 JS 脚本能够让你的网页程序更加丰富多彩。而 ASP.NET MVC 内置了对 AJAX 脚本的支持,因此你可以创建具有更多功能的用户界面。在 ASP.NET MVC 程序中添加 AJAX 支持的第一件事是在视图页面中引用相应的脚本。在 Visual Studio 中创建缺省的 ASP.NET MVC 项目时,模块将为你创建脚本文件夹,所有必需的JS 脚本文件都已经复制到正确的位置。在 Visual Studio 的解决方案管理器中,你可以看到这个文件夹中的一些脚本文件(图 5)。
图 5. AJAX 支持文件已复制到 ASP.NET MVC 程序中。
虽然可以在该文件夹中添加定制的脚本,但 ASP.NET MVC 安装包提供的脚本提供了一个便利的起始点。为了启用这些脚本,你需要使用以下方式在 .aspx 文件中引用:
script src="/Scripts/MicrosoftAjax.js" type="text/javascript"/script script src="/Scripts/MicrosoftMvcAjax.js" type="text/javascript"/script |
利用适当的引用,你可以使用内置的 AJAX helper 对象,创建指向控制器操作的操作链接,并接着返回数据。然后,可以利用该数据更新用户界面:
div id="hello-world-element"/div %= Ajax.ActionLink("Show Ajax Message", "AjaxMessage", new { Name = "TestUser" }, new AjaxOptions { UpdateTargetId = "hello-world-element" })% |
以上代码将生成基于脚本的链接,它触发 Home 控制器中的 AjaxMessage 操作。对于 AJAX 的实现,无需在控制器中编写任何专用的代码:返回 HTML 代码片段的常规代码就足够了。不过,如果想要返回对象可使用 JS 处理,那么应以 JSON 编码的格式返回。ASP.NET MVC 利用 JSON helper 方法可以方便地返回这种对象,该方法可从控制器类获取。以下是实现这种操作方法的示例:
public JsonResult JsonTest() { var quickObject = new { Name = "John Doe", Age = 37, City = "Salt Lake City" }; return Json(quickObject); } |
你还可以使用常用的 jQuery 库,它有助于在试图页面中编写 JS 代码。jQuery 是一个开源库(与模拟对象库类似),并且在 ASP.NET MVC 程序中直接使用。实际上,ASP.NET MVC 自带版本 1.3.2 的 jQuery,并且只需通过指向相应的 .js 文件就可引用:
script type="text/javascript" src="/Scripts/jquery-1.3.2.js"/script |
同样,在添加该引用之后,你可以开始使用相应的库。例如,想要为标题添加一些动画效果,你可以调用 jQuery 支持的 fadeOut 方法。这种方法利用一个时间值(单位是毫秒)来更改 HTML 元素(比如 DIV 标签中定义的元素)的显示。以下为示例:
script type="text/javascript" function FadeTextOut() { $("#my-id").fadeOut(1500, null); } /script a href="#" onclick="javascript:FadeTextOut();"Click me/a p div id="my-id" style="font-size: x-large;"Hello, World!/div /p |
如果还不熟悉 jQuery,那么可在 jQuery 官方网站上查阅相应的使用指南,或者访问 Developer.com,学习一些入门知识。
总结
在本文中,你学习了对于几乎所有 ASP.NET MVC 程序都非常常见而有不同的三种需求:本地化、单元测试和 AJAX 支持。对于常规的 ASP.NET WebForm 程序,以前已经有其他文章讲述了这些内容,但 ASP.NET MVC 要求更高的技术。例如,在 ASP.NET MVC 应用程序中,可以使用多种方式进行本地化:使用资源字符串,可以有效地为每种语言生成不同的视图。同样, ASP.NET MVC 应用程序不便于使用 ScriptManager 组件,因此在编写 AJAX 程序时你需要改变策略。
最后,对于 Microsoft .NET 平台提供的网页技术,ASP.NET MVC 是一个很好的补充。对于你编写的所有网页程序,ASP.NET MVC 可能并非最理想的解决方案,但熟练的 ASP.NET MVC 技术可以让你如虎添翼,飞的更远更高。
原文:Localizing, unit testing and using AJAX in ASP.NET MVC applications
作者:Jani Järvinen