从ASP.NET Web Form到ASP.NET MVC,我们感到既熟悉又陌生。它是ASP.NET Web Form的一个增强,一个替代,还是一个替补?我们做Web开发两者都需要了解掌握吗……
相信很多朋友和我一样,在学习ASP.NET MVC的路上会遇上许多疑问,以至于甚至很多人只是大概了解下,感觉和ASP.NET Web Form差不多。
本文,就是总结一些自己学习过程中的随想,希望能给你解一些惑。
0. Web是怎样工作的
有助于理解ASP.NET Web Form和ASP.NET MVC之间区别和更好学习ASP.NET MVC的重点之一就是要理解Web是怎样工作的。
相信很多人有这样的经历:在使用ASP.NET控件轻松创建Web页面入门Web开发之后,却会被ASP.NET复杂的页面生命周期,服务器控件,页面回调这样一些概念搞得晕头转向。以至于许多像我一样的初级程序员被一个控件和页面生命周期的准确描述和理解被面试长官拒绝无数次,这里当然有个人的技术熟练度和没有努力等问题,但是不免也会疑问,Web真的有这么复杂么?
我不是计算机专业毕业,没有学过网络技术。但是我相信,像Web的工作原理,HTTP等这样一些概念,即便是学过理论也需要在工作中的不断接触才会有更深的理解。我对软件开发的学习是从ASP.NET开始的,在此之前我不知道Web是怎样工作的,因此一路走来,就像一个成绩不好的孩子,每一个问题都是要老师讲了之后才知道怎样做,从来不敢说自己掌握了技术。其实这样也好,学到一点小小的技巧都会感到很高兴。
直到看了《RESTful Web服务》,才开始关注Web的工作原理。这本书讲的是REST,可事实上REST是Web的最佳体验,可以说是你必须理解Web的基本工作原理,才能理解REST的概念。在看了这本书以及之后看过一些HTTP相关的书籍和文章之后,才恍然大悟,原来Web是简单的。
它简单得就像我们现在的短信通信:你发送一条消息给另一个人,而另一个人给你回复一条信息。
我们应该都了解移动联通等短信服务,我们看一条联通的短信服务(10010):
0.3G专区
1.话费及积分
2.账户查询
3.客户服务
4.业务办理
5.增值业务
6.省份专区
请直接发送相应序号到10010进行业务办理.
这样的短信服务,相信大家并不陌生。10010是一台短信服务器,它有很多信息,如果你想看关于3G的信息,你就发送0到10010;10010根据请求短信中的序号知道你是要咨询3G业务,于是就把3G相关的一条短信发给你。其中的序号是一个标识,它告诉服务器应该响应哪条信息。
Web其实也是这样的,客户机发送一条消息给服务器,服务器回一条消息给客户机。并且两者之间传输的仍然是像短信一样的文字,只不过其中的标识复杂了,因为Web的文档远不像短信那么简单,Web服务器有大量的文档,每种文档有复杂的格式,并且这些文档内容可能是动态生成。因此这个请求的标识变得复杂,它可能包含大量的信息,比如请求的文件类型,请求文档的编号,路径,以及其他大量相信。而服务器能够理解这个“复杂的标识”,能根据这个复杂的标识猜出客户机想要的具体的文档内容和类型。并且除了文档内容,服务器仍然可能附带复杂的标识信息,比如告诉客户机这是一个Word文档,你还可以用Word相关工具打开这个文档。
看,Web就是这么简单。它就是关于向服务器发送一个文档以请求另一份文档的事。为了相互之间能给更好的协调,每个信息另外加上一些大家都能懂的标识,这就是HTTP协议。比如请求部分包含Header,HTTP版本,主机地址路径,请求的具体信息(Body)。
就这么简单的事,可是ASP.NET就要发过来再回调过去,搞得没完没了的,真实晕头转向。
1. ASP.NET,ASP.NET Web Form和ASP.NET MVC
其实很多时候我们把ASP.NET和ASP.NET Web Form当做一回事了,认为.NET的Web开发就是ASP.NET了,这里其实是一个小误区。
根据第一节介绍的Web工作机制,我们来分析这张图,这是我手画的草图,存在不完整和不严密的地方,但大体可以这样理解。
IIS是一个网络组件,属于TCP/IP协议的应用层,你安装,或者不安装,它就在那里!^_^
IIS有2个主要基础功能:1,接收传输层的数据,并把数据传递给上层应用程序如(ASP.NET)。2,接收上层应用程序的数据,并把数据发送给传输层发送到Internet网络。
所以,ASP.NET只是IIS服务器组件的一种接收和处理数据的方式。IIS提供了接收和处理数据的能力。ASP.NET提供一种开发Web应用程序的基本框架和基础能力。你不用Web Form或者MVC,仍然可以开发ASP.NET应用程序。并且还可以有其他的应用程序框架来和IIS交互。
我们所知道的IHttpHandler,HttpContext等属于ASP.NET基础框架。ASP.NET基础框架提供的能力大体可以这样理解:
1. 接收来自IIS的原始数据,这个数据就是一个Http请求的数据文本,我们来看一个Windows Azure Storage Service API的例子:
PUT http://myaccount.blob.core.windows.net/mycontainer/myblockblob HTTP/1.1
x-ms-version: 2009-09-19
x-ms-date: Sun, 27 Sep 2009 22:33:35 GMT
Content-Type: text/plain; charset=UTF-8
x-ms-blob-type: BlockBlob
x-ms-meta-m1: v1
x-ms-meta-m2: v2
Authorization: SharedKey myaccount:YhuFJjN4fAR8/AmBrqBz7MG2uFinQ4rkh4dscbj598g=
Content-Length: 11Request Body:
hello world
任何Web请求的数据都是类似这样的,不管是ASP.NET还是PHP还是Ruby On Rails等。
2. 将这个纯文本转化为HttpContext.Request对象,这使得我们可以获取请求中的信息,从而做出相应的事情。比如Url,Headers,Param,Stream等等
3. 提供一种方式让开发者可以编辑响应文本。不管是转发一个静态文件,还是动态构造一个文档,你可以在继承自IHttpHandler的一个类中自由发挥。你可以设置Header,Body,响应代码等。这些可以设置在HttpContext.Response对象中。
4. 将开发者编辑的对象(HttpContext.Response)转化为响应文本,以下是一个例子:
HTTP/1.1 201 Created
Transfer-Encoding: chunked
Content-MD5: sQqNsWTgdUEFt6mb5y4/5Q==
Date: Sun, 27 Sep 2009 22:33:35 GMT
ETag: 0x8CB171BA9E94B0B
Last-Modified: Sun, 27 Sep 2009 22:30:15 GMT
Server: Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0
5. 把这个文本发送给IIS。
IIS再转发给传输层,传输层将内存中的数据添加到网际层,网际层把这些数据发送到Internet。
但是如果一个站点全是用IHttpHandler来开发,这无疑是很麻烦的,事实上我们可以自己来处理请求和响应文本,ASP.NET这提供了基础的Web开发能力。为了提高效率我们需要另外的模板化的方式来设置响应文本,这就是Web Form。而IHttpHandler作为了一种高级的开发,也转化为某些在Web Form不能处理的一种替补。
所以,为了提高一种模板化的方式高效的开发ASP.NET 应用程序,微软推出Web Form‘。它提供一种模板的机制编辑Html,并且提出Web服务器控件这样一种概念,使我们既可以对aspx页面直接编辑,也可以与后台交互,比如取值和赋值。
然而Web Form过于热心,本来每一次用户提交,点击一个按钮都是一次不同的交互,都要遵循前面描述的过程。Web Form为了使开发者更方便的获取请求信息(控件的值),从而弄出回调这样的机制,我们开发确实简单了,直接在后台获取某个控件的引用就可以取值。但是我们看到这确实与Web的简洁简单大大违背的,并且使很多开发人员远离了对Web工作机制的真正理解。
而ASP.NET是另一种模板化的开发Html页面的机制。它更遵循Web的工作方式,我们后面会分析。
所以ASP.NET MVC仍然是基于ASP.NET,这就是许多人纳闷:MVC好像是另一种全新的方式,为什么还跟ASP.NET有关系,莫非这个MVC不纯,不正宗?看了这样的分析,相信你会明白。
而且,你会觉得开发一个自己的ASP.NET XXX都是可能的。O(∩_∩)O哈哈~
2,从可测试性角度理解ASP.NET MVC
对精通ASP.NET Web Form的朋友来说,显然对于ASP.NET MVC感觉有点多余,比较ASP.NET Web Form已经比较强大足以处理所有需求。那如果它仅仅是另一种替代方式,那学习就没有多大意义了。
可是为什么许多人说ASP.NET MVC才是未来呢?
如果你买了一本和绝大多数ASP.NET Web Form的书一样的,教你怎么使用控件或者怎样开发的书,估计你很难弄清这个问题。事实上很多书光明正大的在封面上写着ASP.NET教程,里面却讲着Web Form,Web服务器控件,这本身是有概念错误的。
我建议的书籍是《ASP.NET MVC实战》(ASP.NET MVC In Action),当然其他书我没有看不好评价(但是不难猜测许多和以前的asp.net教程一样的书)。这本书有两个理由值得推荐:
1. 讲MVC背后的开发思想,而不仅仅是技术
2. 强大可测试性,可测试性是学习ASP.NET MVC的关键
这一节,我们就从可测试性角度来分析。
相信只有比较有经验的开发者才会在ASP.NET Web Form中使用单元测试,一般人不会有这种概念。这不仅是开发者自己的意识和技能问题,ASP.NET Web Form本身是不易于测试的。
在ASP.NET Web Form中,后台代码(.aspx.cs)和页面(.aspx)耦合在一起。有人说这两个文件明明不是分开的么,但是请问这两者之间可以独立存在么?不要说用多个aspx页面指向一个aspx.cs文件,这样同样不是独立。在.aspx.cs页面中,大量存在着aspx中的控件引用,离开aspx就无法生存。这就是Web Form为了让开发者最方便的获取请求中的信息(控件的值)所设计的这样一种方式。结果使得我们想分离出一个逻辑功能很困难,因为几乎所有aspx.cs中的方法都涉及控件的引用(取值和赋值),也许你可以定义一个分离的类中包含某个控件,但是请问怎样构造这个控件来做单元测试,也许你又会说在最下面定义一些参数,在调用的时候做一次控件值到参数的转换。问题是你会这么做么?
所有的罪魁祸首在于回调,在于Web Form试图让开发者最简单的和页面交互。
而ASP.NET MVC抛弃了这种思想,把两者之间完全隔离开来,这不仅分离了职责,并且没有了控件引用实行了可测试性。当然这只是实现可测试性的其中一个方面。
3. 重大区别之一---更符合Web工作机制,去掉Page复杂的生命周期
在ASP.NET MVC中没有了回调机制。
ASP.NET的工作流程如下:
1. ASP.NET MVC从ASP.NET基础框架获取请求数据(这和Web Form一样)
2. 路由到正确的Controller中的Action
3. Action准备要显示的数据ViewData,并将ViewData传递给View
4. View按模板显示ViewData中的数据,ASP.NET MVC后面会按模板定义转化为Html文本
5.用ASP.NET基础功能将Html页面发送出去
之后,发送到客户机的也没将不会和Action有任何关系,不需要回调回去取值,这就看起来更像Web的工作机制。
4. 重大区别之二---Controller传递对象而不是直接给View中的控件赋值
那ASP.NET MVC是怎样实现这种分离的。秘密在于传递对象而不是直接赋值。
在ASP.NET Web Form中,后台程序需要获取页面中控件的值,因此需要把整个页面回调会服务端。但是ASP.NET MVC取消了这个机制,因此我们只能按传统的表单的方式取值了。而Action对于View中控件的赋值,却转化为传递一个Dictionary<string,object>对象,这样Controller和View之间唯一的耦合只是View的名称。而视图的唯一任务是将对象转化为HTML。因此在ASP.NET MVC中几乎没有了控件的概念,因为View中的控件不需要被引用,它们仅仅是一个现实HTML的面板而已。
由此可见在ASP.NET Web Form中从aspx页面控件取值和赋值的可能性被去掉了,这使得Action中不再具有无法构造的控件引用,而只是普通的参数,因此使得测试成为可能。
5. 可测试性的深入讨论
学习ASP.NET MVC,我们知道,用户提交的表单数据,或者Url中的参数被自动提取为Action的参数,这使得Action中的参数总是可构造的。然而完整的可测试性还应该考虑以下问题:
ASP.NET MVC只能从请求信息中提取Url参数和表单数据,如果需要获取Header,Stream,仍然需要与ASP.NET运行时关联,及HttpContext,这个对象在Web Form时代是不可构造的,因此也是不可测试的。当然据说ASP.NET MVC提供了可以构造的HttpContextBase等可构造的对象,因此使得这样的需求可以实现单元测试。这是一大好消息。只要在ASP.NET层面提供了运行时对象的可构造,这样所有ASP.NET XXX都是易于测试的了,当然在ASP.NET Web Form中控件还是不可构造的,因此只能说,目前ASP.NET MVC是完全可测试的。
同时,弱耦合式MVC模式的重要思想。这不仅是软件设计原则,使得软件更具有可维护性,同时他也是可测试的重要因素之一,在高级ASP.NET MVC开发者我们还会学习Ioc这样的思想。它都是使软件可测试和可维护的重要体验。
由此,我们也可以看出,在学习ASP.NET过程中,可测试性观念的重要性。往往因为一般ASP.NET开发者没有这样的观念因此会简单的理解ASP.NET MVC的地位。
6. ASP.NET MVC与ASP.NET Web Form并存,互补
当然ASP.NET MVC与ASP.NET Web Form之间不是非此即彼的关系,它们可以并存于同一个应用程序中。我们可以从他们之间的关系去理解这一点,它们都是基于ASP.NET的一个模板化开发方法。
ASP.NET Web Form提供比ASP.NET MVC要强大很多的方法,并且我们大多数多Web Form的机制非常熟练了。但是随着Ajax的广泛应用,ASP.NET MVC简洁的模式会更受欢迎,并且它符合Web的理念,更重要的,它更易于测试,从而保证项目的质量。从某种程度上说,从ASP.NET MVC中的可测试性或者的软件质量保障的好处,也许会高于从表单获取数据没有Web Form高效的地方。当然,我对ASP.NET MVC也只是在学习的路上,也许ASP.NET MVC和Web Form一样强大。
7. 高级ASP.NET开发
不管是ASP.NET Web Form还是ASP.NET MVC,或者你自己实现的ASP.NET XXX,这些都不是实现完整的Web开发。
模板化的开发方式只是面向浏览器的,它构造的是HTML页面。如果你实现的服务不是面向浏览器,而是面向应用程序,这样的框架就不行了,所以我们构建WCF不能使用ASP.NET Web Form或者ASP.NET MVC,它实际上又是基于ASP.NET的另一个框架。
并且,很多时候我们发现Web Form无法做到的事情,只能用IHttpHandler来实现,记住ASP.NET Web Form和ASP.NET MVC都是原来实现面向浏览器的高效开发的。
反过来,理解了ASP.NET运行时机制,可以很好的学习任何ASP.NET XXX框架。在这之上,你开发一个自己的Web框架都是可能的。事实上笔者正在构造在ASP.NET上开发REST API的框架,它类似于WCF,但是REST风格的,当然也不同于WCF Data Service。
我们看到不论是我的REST框架,还是WCF,还是ASP.NET Web Form,还是ASP.NET MVC;这些都是基于ASP.NET基础框架。ASP.NET是一个强大的Web框架,不要拿Web From所能做的事情当做是ASP.NET所能做的事情。
8. 总结
胡言乱语,没有逻辑,随想随写,切莫道听途说,如有误导,深表歉意!