不带 Web 窗体的 Web 应用程序文档格式.docx

上传人:b****6 文档编号:18647227 上传时间:2022-12-30 格式:DOCX 页数:18 大小:181.85KB
下载 相关 举报
不带 Web 窗体的 Web 应用程序文档格式.docx_第1页
第1页 / 共18页
不带 Web 窗体的 Web 应用程序文档格式.docx_第2页
第2页 / 共18页
不带 Web 窗体的 Web 应用程序文档格式.docx_第3页
第3页 / 共18页
不带 Web 窗体的 Web 应用程序文档格式.docx_第4页
第4页 / 共18页
不带 Web 窗体的 Web 应用程序文档格式.docx_第5页
第5页 / 共18页
点击查看更多>>
下载资源
资源描述

不带 Web 窗体的 Web 应用程序文档格式.docx

《不带 Web 窗体的 Web 应用程序文档格式.docx》由会员分享,可在线阅读,更多相关《不带 Web 窗体的 Web 应用程序文档格式.docx(18页珍藏版)》请在冰豆网上搜索。

不带 Web 窗体的 Web 应用程序文档格式.docx

但进一步的页面单元测试常常有很大困难。

您必须先启动所有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 

ControllerUnitTest

namespaceHelloFromMVC.Tests

[TestClass]

publicclassHelloControllerFixture

[TestMethod]

publicvoidHiThereShouldRenderCorrectView()

TestableHelloControllercontroller=new

TestableHelloController();

controller.HiThere("

Chris"

Assert.AreEqual("

controller.Name);

controller.ViewName);

classTestableHelloController:

HelloController

publicstringName;

publicstringViewName;

protectedoverridevoidRenderView(

stringviewName,stringmaster,objectdata)

this.ViewName=viewName;

this.Name=(string)ViewData["

];

下面将进行几项操作。

实际的测试相当简单:

实例化该控制器,使用预期的数据调用该方法,然后检查呈现的视图是否正确。

我通过创建测试专用的子类覆盖RenderView方法进行检查。

这可以缩短实际创建HTML的时间。

我只关心是否将正确的数据发送到视图以及是否呈现了正确的视图。

我不关心此测试视图本身的底层详细信息。

创建视图

当然,最终我必须生成一些HTML,因此,让我们创建该HiThere视图。

要进行此操作,首先,我将在解决方案中的Views文件夹下创建名为Hello的新文件夹。

默认情况下,控制器将在Views\<

控制器前缀>

文件夹(控制器前缀为控制器类的名称去掉"

Controller"

字样)中查找视图。

因此,对于HelloController呈现的视图,它会在Views\Hello中查找。

解决方案的查找结果如图4所示。

Figure4 

将视图添加到项目中 

视图的HTML如下所示:

<

html>

headrunat="

server"

>

<

title>

HiThere!

/title>

/head>

body>

div>

h1>

Hello,<

%=ViewData["

]%>

/h1>

/div>

/body>

/html>

应注意以下几件事。

没有runat="

标记。

没有form标记。

没有控件声明。

实际上,这看起来更象传统的ASP而不是ASP.NET。

请注意,MVC视图仅负责生成输出,因此其不需要任何Web窗体页面所需的事件处理或复杂控件。

MVCFramework借用了.aspx文件格式作为一种有用的文本模板语言。

如果需要,甚至可以使用源代码,但默认情况下,源代码文件如下所示:

namespaceHelloFromMVC.Views.Hello

publicpartialclassHiThere:

ViewPage

没有页面初始化或加载方法,没有事件处理程序,除了基类声明以外没有任何内容,基类声明为ViewPage而不是Page。

这就是MVC视图所需的一切。

运行该应用程序,导航至http:

//localhost:

端口>

/Hello/HiThere/Chris,您将看到如图5所示的内容。

Figure5 

成功的MVC视图 

如果您看到的并非如图5所示,而是难以理解的意外情况,请不要惊慌。

如果您将HiThere.aspx文件设置为VisualStudio中的活动文档,则当按F5后,VisualStudio将尝试直接访问.aspx文件。

由于MVC视图要求控制器在显示前运行,因此尝试直接导航至该页面将不起作用。

只需将该URL编辑为与图5中所示的内容相匹配,即可正常工作。

MVCFramework如何知道调用我的操作方法?

该URL甚至没有文件扩展名。

答案是URL路由。

如果您仔细查看global.asax.cs文件,则会看到如图6所示的代码段。

全局RouteTable会存储Route对象的集合。

每个Route说明一个URL窗体以及对其进行何种操作。

默认情况下,会向该表中添加两个路由。

第一个是该方法的内容。

它说明每个URL在服务器名后均由三部分组成,第一部分应为控制器名,第二部分为操作名称,而第三部分为ID参数。

RouteTable

publicclassGlobal:

System.Web.HttpApplication

protectedvoidApplication_Start(objectsender,EventArgse)

//ChangeUrl=toUrl="

[controller].mvc/[action]/[id]"

//toenableautomaticsupportonIIS6

RouteTable.Routes.Add(newRoute

Url="

[controller]/[action]/[id]"

Defaults=new{action="

Index"

id=(string)null},

RouteHandler=typeof(MvcRouteHandler)

});

Default.aspx"

Defaults=new{

controller="

Home"

action="

id=(string)null},

Url="

此默认路由是能让我的HiThere方法得以调用的路由。

请记住此URL:

http:

//localhost/Hello/HiThere/Chris?

此路由将Hello与控制器、HiThere与操作以及Chris与ID一一对应。

MVCFramework随即创建HelloController实例,调用HiThere方法,然后将Chris作为ID参数的值传递。

此默认路由为您提供了许多功能,但您也可以添加自己的路由。

例如,我想要一个真正友好的站点,好友们只需输入他们的姓名即可获得个性化的问候。

如果我在路由表的顶部添加以下路由

[id]"

Hello"

},

随后,我只需访问,我的操作仍处于调用状态,而我将会看到熟悉的友好问候。

系统如何知道调用哪个控制器和操作?

答案是Defaults参数。

它利用新的C#3.0匿名类型语法来创建一个伪词典。

Route上的Defaults对象可包含任意附加的信息,对于MVC,它还可以包含一些众所周知的条目:

即控制器和操作。

如果URL中没有指定控制器或操作,则其将使用Defaults中的名称。

这就是为什么即使我在URL中忽略它们,但仍可以将我的请求映射到正确的控制器和操作。

还有一件事需要注意:

还记得我说过“添加到表格的顶部”吗?

如果您将其置于底部,将会出现错误。

路由根据先到先得的原则进行工作。

当处理URL时,路由系统会自上至下浏览表格,并且使用第一个匹配的路由。

在本例中,默认路由"

匹配,因为它们是操作和ID的默认值。

这样,它会继续查找ChrisController,但我没有控制器,因此会出现错误。

稍大的示例

现在,我已经说明了MVCFramework的基础知识,将为您展示一个更大的示例,实现比仅显示字符串更多的功能。

wiki是一种可以在浏览器中进行编辑的网站。

可以轻松地添加或编辑页面。

我使用MVCFramework编写了一个小型的示例wiki。

“编辑此页面”屏幕如图7所示。

Figure7 

编辑主页 

您可以检查本文的代码下载以查看如何实现底层wiki逻辑。

现在我想重点说明MVCFramework如何使Web上的wiki获取变得简单。

让我们先设计URL结构。

我想要以下各项:

∙/[pagename]显示该名称的页面。

∙/[pagename]?

version=n显示页面的请求版本,其中0=当前版本,1=以前的版本,以此类推。

∙/Edit/[pagename]打开该页的编辑屏幕。

∙/CreateNewVersion/[pagename]是为提交编辑而传入的URL。

让我们从wiki页面的基本显示开始。

我为它创建了一个名为WikiPageController的新类。

接下来,我会添加一个名为ShowPage的操作。

启动的WikiPageController如图8所示。

ShowPage方法相当简单。

WikiSpace和WikiPage类分别表示一组wiki页面和特定的页面(及其修订)。

此操作只需加载模型并调用RenderView。

但此处的"

newWikiPageViewData"

行是什么意思?

WikiPageControllerImplementationofShowPage

publicclassWikiPageController:

Controller

ISpaceRepositoryrepository;

publicISpaceRepositoryRepository

get{

if(repository==null)

repository=newFileBasedSpaceRepository(

Request.MapPath("

~/WikiPages"

));

returnrepository;

set{repository=value;

publicvoidShowPage(stringpageName,int?

version)

WikiSpacespace=newWikiSpace(Repository);

WikiPagepage=space.GetPage(pageName);

showpage"

newWikiPageViewData

{

Name=pageName,

Page=page,

Version=version?

?

0

我前面的示例说明了一种将数据从控制器传递到视图的方法:

即ViewData词典。

词典非常方便,但也很危险。

它们几乎包含一切内容,您不能获取内容的任何IntelliSense®

,并且由于ViewData词典属于Dictionary<

string,object>

类型,它将消耗内容,您必须计算所有一切。

当您了解在视图中将需要什么数据后,就可以传递强类型化的ViewData对象。

在我的示例中,我创建了一个简单的对象(WikiPageViewData),如图9中所示。

此对象将wiki页面信息带到视图,同时还携带了一些实用工具方法,执行获取wiki标记的HTML版本这类任务。

WikiPageViewDataObject

publicclassWikiPageViewData{

publicstringName{get;

set;

publicWikiPagePage{get;

publicintVersion{get;

publicWikiPageViewData(){

Version=0;

publicstringNewVersionUrl{

returnstring.Format("

/CreateNewVersion/{0}"

Name);

publicstringBody{

get{returnPage.Versions[Version].Body;

publicstringHtmlBody{

get{returnPage.Versions[Version].BodyAsHtml();

publicstringCreator{

get{r

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 高等教育 > 教育学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1