不带 Web 窗体的 Web 应用程序.docx
- 文档编号:5660135
- 上传时间:2022-12-30
- 格式:DOCX
- 页数:18
- 大小:181.85KB
不带 Web 窗体的 Web 应用程序.docx
《不带 Web 窗体的 Web 应用程序.docx》由会员分享,可在线阅读,更多相关《不带 Web 窗体的 Web 应用程序.docx(18页珍藏版)》请在冰豆网上搜索。
不带Web窗体的Web应用程序
我从事专业开发迄今为止已有15年,在此之前,我利用业余时间从事开发至少也有10年了。
与我这一代的大多数人一样,我是从8位计算机起步,然后转用PC平台的。
随着计算机的复杂性日益增加,我编写的应用程序涵盖了从小型游戏到个人数据管理再到控制外部硬件的各项功能。
不过,在我职业生涯的前半段,我编写的所有软件都有一个共同点:
即,都是运行在用户桌面上的本地应用程序。
我最早是在90年代初期听说万维网这件新生事物。
那时我发现,通过构建Web应用程序,可以让我输入我的考勤卡信息而不必再费时费力从工作场所赶回办公室。
一言以蔽之,我感觉很是困惑。
我当时满脑子是面向桌面的理念,很难接纳这种无状态的Web。
要添加很多让人头疼的调试、我没有UNIX服务器的超级用户访问权限,再加上这个奇怪的角括号,这些因素使年轻时的我止步不前,又重返桌面开发渡过了几年时光。
我远离了Web开发领域,虽然这领域显然很重要,但我并没有真正理解其编程模型。
然后,Microsoft®.NETFramework和ASP.NET发行了。
尽管它与桌面应用程序编程有许多相似之处,但终于有了可以让我从事Web应用程序编程的框架。
我可以构建窗口(页面),将控件与事件挂钩,而设计器使我不必处理那些讨厌的角括号。
最妙的是,ASP.NET会通过查看状态自动为我处理Web的无状态性质!
我又重新找回了程序员的快乐...至少在一段时间内是如此。
随着经验的增加,我的设计内容也随之丰富。
我早已掌握了几种最佳实践,并将其应用到桌面应用程序编程。
其中的两种就是:
∙分离关注点:
不要将UI逻辑与基础行为混合在一起。
∙自动单元测试:
编写自动测试以验证您的代码是否按预期执行。
这些是适用于任何技术的基本原则。
分离关注点是一项可帮助您处理复杂问题的基本原则。
在同一个对象内混合多种责任(如计算剩余的工时、设置数据格式并绘图)会给维护带来很大的负担。
而自动测试对于获得生产质量的代码同时仍保持条理性至关重要,尤其是当您更新现有项目时更是如此。
ASP.NETWeb窗体使入门变得非常简单,但另一方面,要将我的设计理念应用到Web应用程序却并非易事。
Web窗体坚持以UI为侧重点;其基本单位为页面。
首先设计UI并拖曳控件。
只需将应用程序逻辑融入页面的事件处理程序(与为Windows®应用程序启用的VisualBasic®非常相似)就万事大吉,这一点非常吸引人。
但进一步的页面单元测试常常有很大困难。
您必须先启动所有ASP.NET,然后才能在“页面”对象的生命周期内运行该对象。
尽管可以通过发送HTTP请求到服务器或自动化浏览器来测试Web应用程序,但这类测试非常脆弱(更换一个控制ID测试就会中断)、难以设置(您必须以完全相同的方式在每位开发人员的计算机上设置该服务器)并且运行缓慢。
当我开始构建更复杂的Web应用程序时,Web窗体提供的抽象概念(如控件、视图状态和页面生命周期)就开始添乱而不是帮忙了。
我需要花越来越多的时间来配置数据绑定(并编写大量的事件处理程序对其进行正确配置)。
我不得不想办法缩减视图状态的大小以便更快加载我的页面。
Web窗体要求每个URL均存在物理文件,这对于动态站点(例如wiki)非常困难。
而成功编写一个自定义的WebControl是一个非常复杂的过程,需要全面了解页面生命周期和VisualStudio®设计器。
自从在Microsoft工作开始,我就一直与其他人分享关于各种.NET难题的体验并希望可以解决一些难题。
最近,作为开发人员参加有关模式与实践的Web客户端软件工厂项目(时,我遇到了一个这样的机会。
特别是,模式与实践交付的内容之一就是自动单元测试。
在Web客户端软件工厂中,我们建议使用ModelViewPresenter(MVP)模式构建可测试的Web窗体。
简而言之,MVP并非将您的逻辑放入页面中,而是让您构建自己的页面,页面(View)只需调用单独的对象,即Presenter。
Presenter对象随即执行响应视图上活动必需的任何逻辑,通常通过使用其它对象(Model)访问数据库、执行业务逻辑等。
一旦这些步骤完成后,Presenter会更新视图。
这种方法提供了可测试性,因为表示器从ASP.NET管道中隔离出来;它与视图通过界面进行通信并可脱离页面独立进行测试。
MVP的这种功能实现有点笨;您需要单独的视图界面,并且您必须在源代码文件中编写许多事件转发函数。
但如果您想要在Web窗体应用程序中得到可测试的UI,这差不多是最佳途径。
任何改进均需要在基础平台中做出更改。
模型视图控制器模式
幸运的是,ASP.NET团队听取了象我这样的开发人员的意见,并且已经着手开发一种新的Web应用程序框架,该框架与您所熟知并喜爱的Web窗体处于同一层级,但采用一组完全不同的设计目标:
∙使用HTTP和HTML—不隐藏。
∙可测试性贯穿整个框架之内。
∙几乎在每个点均可扩展。
∙对输出进行总体控制。
由于此新框架基于模型视图控制器(MVC)模式,因此其名称为ASP.NETMVC。
MVC模式最初在70年代发明,是Smalltalk技术的一部分。
正如我将在本文中所展示的,它实际上非常适合Web的性质。
MVC将您的UI分为三种不同的对象:
用于接收和处理输入的控制器;包含您域逻辑的模型;以及用于生成输出的视图。
在Web环境中,输入为HTTP请求,而请求流程与图1类似。
Figure1 MVC模式请求流程 (单击该图像获得较大视图)
这实际上与Web窗体中的过程完全不同。
在Web窗体模型中,输入进入页面(视图),然后视图负责处理输入并生成输出。
而MVC中这些责任是分开的。
因此,您可能立即会产生以下一种想法:
“嘿,这太好了。
我应该如何使用它?
”或“为什么我要编写这些对象,以前只需要编写一个对象?
”这两个问题都问得很好,最好通过示例来进行解释。
因此,我将使用MVCFramework编写一个小型Web应用程序以说明其优点。
创建控制器
要继续进行,您将需要安装VisualStudio2008并获得MVCFramework的副本。
在撰写本文时,ASP.NET扩展的2007年12月社区技术预览(CTP)中已提供了这些内容(CTP和MVC工具包,其中包括一些非常有用的帮助程序对象。
一旦下载并安装CTP后,您将在“新建项目”对话框中获得名为“ASP.NETMVCWeb应用程序”的新项目类型。
选择“MVCWeb应用程序”项目后,会为您提供一个与常用网站或应用程序稍有不同的解决方案。
该解决方案模板会创建一个带有一些新目录的Web应用程序(如图2中所示)。
特别是Controllers目录包含各种控制器类,而Views目录(及其所有子目录)包含了各种视图。
Figure2 MVC项目结构
我将会编写一个非常简单的控制器,返回URL中传递的名称。
右键单击Controllers文件夹并选择“添加项目”以显示常用的“添加项目”对话框以及一些新增加的内容,包括MVC控制器类和几个MVC视图组件。
在此例中,我将添加一个非常富有想象力、名为HelloController的类:
usingSystem;
usingSystem.Web;
usingSystem.Web.Mvc;
namespaceHelloFromMVC.Controllers
{
publicclassHelloController:
Controller
{
[ControllerAction]
publicvoidIndex()
{
...
}
}
}
控制器类比页面简单得多。
实际上,唯一真正必需做的就是从System.Web.Mvc.Controller中衍生并将[ControllerAction]属性置于您的操作方法中。
操作是调用以响应特定URL请求的一种方法。
操作负责执行所需的一切处理,然后呈现一个视图。
我将通过编写一个将名称传递到视图的简单操作着手,如下所示:
[ControllerAction]
publicvoidHiThere(stringid)
{
ViewData["Name"]=id;
RenderView("HiThere");
}
操作方法会通过ID参数从URL接收该名称(稍后会介绍方法),将其存储在ViewData集合中,然后呈现名为HiThere的视图。
在讨论如何调用此方法,或该视图的显示内容之前,我希望说一说可测试性。
还记得我之前关于测试Web窗体页面类有多难的评论吗?
控制器的测试简单得多。
实际上,控制器可以直接实例化,而调用操作方法无需任何附加的基础结构。
您不需要HTTP上下文,也不需要服务器,只要测试工具即可。
作为示例,我在图3中为此类包括了VisualStudioTeamSystem(VSTS)测试单元。
Figure 3 ControllerUnitTest
namespaceHelloFromMVC.Tests
{
[TestClass]
publicclassHelloControllerFixture
{
[TestMethod]
publicvoidHiThereShouldRenderCorrectView()
{
TestableHelloControllercontroller=new
TestableHelloController();
controller.HiThere("Chris");
Assert.AreEqual("Chris",controller.Name);
Assert.AreEqual("HiThere",controller.ViewName);
}
}
classTestableHelloController:
HelloController
{
publicstringName;
publicstringViewName;
protectedoverridevoidRenderView(
stringviewName,stringmaster,objectdata)
{
this.ViewName=viewName;
this.Name=(string)ViewData["Name"];
}
}
}
下面将进行几项操作。
实际的测试相当简单:
实例化该控制器,使用预期的数据调用该方法,然后检查呈现的视图是否正确。
我通过创建测试专用的子类覆盖RenderView方法进行检查。
这可以缩短实际创建HTML的时间。
我只关心是否将正确的数据发送到视图以及是否呈现了正确的视图。
我不关心此测试视图本身的底层详细信息。
创建视图
当然,最终我必须生成一些HTML,因此,让我们创建该HiThere视图。
要进行此操作,首先,我将在解决方案中的Views文件夹下创建名为Hello的新文件夹。
默认情况下,控制器将在Views\<控制器前缀>文件夹(控制器前缀为控制器类的名称去掉"Controller"字样)中查找视图。
因此,对于HelloController呈现的视图,它会在Views\Hello中查找。
解决方案的查找结果如图4所示。
Figure4 将视图添加到项目中 (单击该图像获得较大视图)
视图的HTML如下所示: