十月 2006 - 随笔

“ASP.NET,抬起头来,让朕瞧瞧”

看到这个题目,你一定会很吃惊。其实,最初,我只是想把这篇blog命名为《ASP.NET,掀起你的盖头来》,但后来,还是抑制不住心中的兴奋之情,换成了这个霸气十足的题目。是的,我真的很兴奋,毕竟,一个礼拜之前,我对这些东西知之甚少,我整整用了一个礼拜的时间才把这些东西的来龙去脉给理个清楚。兴奋之余,想起了《康熙大帝》中那句“抬起头来,让朕瞧瞧”的经典,于是索性把题目改成了《ASP.NET,抬起头来,让朕瞧瞧》。

如今的程序员,其审美观何等挑剔,差异又何等巨大,然ASP.NET这位美女却独领风骚,何哉?大凡我们说某某某“美”,如果是外在的美,那总是经不起时间的考验和众人对美的差异定位,而如果是内在美,则时间无法洗去其气质,众人亦无旁词。故欲知ASP.NET美之何在,当瞧其内在,方可知晓。

 

我在CSDN上逛的时候,无意中发现了《[翻译]了解ASP.NET底层架构.doc》这篇文章,看完之后,一头雾水,但又似乎意犹未尽,于是耐心下来,对于每一处有疑点的地方慢慢琢磨,查资料,向我的同事也是好友qwliang请教,(我的很多疑惑点正是因为有他的指导和帮助才得以得到解决,谢谢他)。反反复复的看了几遍,终于看懂了这篇文章,也“瞧”见了ASP.NET的美。

我本来想针对自己已经形成的理解写一个系列,但是考虑到近期时间比较紧,而且最终写出来的东西,大多还是“剪刀+口水”的产物,还不如把自己的在分析分析asp.net底层运行原理过程中,搜索到的比较有价值的一些资料共享上来,大家“仁者见仁,智者见智”。我在后面附带介绍自己对这些文章的评价,希望能帮助你理解分析。

在分析的过程当中,充分利用Reflector是必要的。因为通过它,你可以看到实际的代码(尽管不一定和源代码一模一样)。如果说文字是有二义性的,那么,代码是没有的,通过分析代码,你可以更容易理解文字表达的内容。

 

另外,附上我的一些个人认识:

1 几个名词解释:

A: XX工厂(Factory):生成某个对象运用了工厂模式,负责生成(生产)对象任务的对象叫做工厂。工厂模式是一种构建模式,通过附件2你应该能够理解。

B: CLR寄宿(Host) :不要被这个名词吓倒,其实没有什么,CLR寄宿,实际上就是在非托管应用程序中加载CLR。一个非托管应用程序(比如sql server2005)需要运行托管代码(比如C#写的存储过程),那么就需要在它的进程当中加载.NET运行时CLR,也就是说CLR要寄宿在运行sql server的进程当中。

其实,从生活中来看“寄宿”这个词也可以帮助你理解。假如你和你的家人住在一起,那我们不会说你寄宿在你家,如果哪天你来了一个远房亲戚住在你家,他就是寄宿在你家。对于一个托管程序,你用Dependency这个工具来看,你会发现,它的运行要依赖于MsCoree.dll,而对于一个非托管程序,则应该不会看到这个依赖(Dependency只能看到静态依赖关系),因为寄宿CLR一般是通过LoadLibrary来动态加载的(这个我不敢肯定,但是我看了好几个.exe.dll都没有,比如w3wp.exe,inetInfo.exe等)。

关于寄宿的细节,你可以参考《.NET框架程序设计》(修订版)中的1.3节《加载.net运行时》和20.2CLR寄宿》。

C: 应用程序域(AppDomain):应用程序域从逻辑上来说,它类似于进程,它是一个逻辑上的容器。“域”的概念,其实也就是一个范围的概念,就好像以前的跑马圈地,圈住一块地之后就说这是我的地域范围。从实现上来说,AppDomain也是System命名空间中的一个类,你可以通过Reflector看到这个类的信息。你也可以参考《.NET框架程序设计》(修订版)中的20.3《应用程序域》。

D: 容器(Container) 容器就是包含其它对象的对象。

E: 管道:以前对管道的理解是两个进程通过管道来进行通信,比如在IIS5中,inetinfo.exe通过“命名管道”将请求交给aspnet_wp.exe(之所以称为命名管道,是因为给这个管道起了一个随机的名字)。现在又出来了一个http 管道(http pipeline),但是这回却是在同一个进程(比如IIS6.0w3wp.exe)里面,这是怎么回事?让我们来看看“管道”的本质,我们分析一下实际生活中的管道,我们看到管道具有下面两个特征:

a  从里面流过的东西来看:东西从管道一头进入,从另外一头出来,东西还是原来的东西。

b  管道从外部形态来看:它连通了两个不同的地方,也就是说它代表着一种流向,一种流程,一种顺序。

是的,我们计算机中的术语和生活中的概念是相通的。我们这里说的HTTP管道,就是指Http ModuleHttp Handler这些对象。而在这些HTTP管道流过的东西是同一个对象,那就是Http Context对象。在Http ModuleHttp Handler这些对象中对Http Context对象的处理,不过是对Http Context对象中的内容进行改变(最大的改变就是给Response对象赋上内容),但是没有改变它的结构。

2 几个容易造成误解的概念:

A:Http Application和我们在页面中使用的Application对象:这两者是不同的。前者代表着我们整个应用程序,对于我们的每个请求,HttpApplicationFactory都会分配一个Http Application对象,这个对象将管理着这个对请求的处理逻辑,或者说它是事件调度中心,你可以看到我们的Global.asax实际上就继承了Http Application。我们在页面中使用的Application是一个状态的概念,它是HttpApplicationState的一个实例,并且是“嵌”在httpContext对象上的一个子对象。

B:.NET运行时和HTTP运行时:NET运行时即是CLR,它的核心是MsCorEE.dll。后者是HTTP RunTime,它是System.webhttpRuntime类的实例。HttpRuntime负责Http Application, Http Context的创建和初始化等工作。这两者是不同的。

C: Http Application Http Context Http ModuleHttp Handler

对于每个请求都被路由到一个HttpApplication对象上.HttpApplicationFactory类根据应用程序的负载为你的ASP.NET应用创建一个HttpApplication对象池并为每个请求分发HttpApplication对象的引用. 这里我再次强调,HttpApplication的主要职责是作为Http管道的事件控制器,httpApplication它本身对发送给应用程序的数据一无所知-它只是一个通过事件来通讯的消息对象.它触发事件并通过HttpContext对象来向被调用函数传递消息.实际的当前请求的状态数据由HttpContext对象维护。你可以用Reflector看一看HttpContext类,里面包含着Request,Response,Application,ServerSession等表示状态的对象。其实,HttpContext本身也表示一种状态,它还有两个很重要的属性,CurrentItems,前者用来代表自己,后者是可以存储任何对象的集合,你不要小看后者,它真的非常有用。鉴于自己与Context曾经有过一段情史,我将在以后写篇blog详细介绍它。

httpModule,有人说是它是“监视器”,有人说是“过滤器”,他们都是从不同角度来看httpModule,所以都是对的。httpModule提供了对请求进入http Handler处理之前的预处理和经过http handler处理后的事后处理,既然可以预处理,当然可以实现拦截请求,不交给http handler去处理,实现“过滤”的功能。从另外一个角度上来说,一旦有请求到来,便会初始化httpModule(httpApplication中有负责初始化httpModule的InitModules()方法),当然也就意味着httpModule监视着请求(也就是“监视器”的来源),毕竟它是我们能够对请求进行处理的开始。需要说明一点的是,ASP.NET只是为我们提供了这个能力,你需要自己去添加事件代码来实现控制,比如你可以在Global.asax中的事件处理函数中添加代码,你也可以自己定义http module.在附件4《asp-net framework深度历险.pdf》你可以看到具体的实例。至于http Handler,我们的页面其实就是一个http Handler,你可以从System.Web.UI.Page类(我们所有页面的基类)的声明中看到它要实现IHttpHandler接口。你可以翻阅《.NET程序设计技术内幕》这本书的8.5《图形控件》看看自己定制实现http Handler的好处。

但是,我不同意在附件4asp-net framework深度历险.pdf》中所说,认为请求是一个单线流式的经过Http ApplicationFactory->Http Application-> Http Module -> Http Handler ->…。从附件1[翻译]了解ASP.NET底层架构.doc》的图6也可以看到,所有的处理起点是在最左边的ASP.NET开始,为什么呢?实际上Http ModuleHttp Handler都是“嵌”在Http Application上的,整个流程是由http Application进行调度的。从另外一个角度上来说,http Application的大部分功能都是由Http Module来实现的,这些Http Module实际上就是在http Application启动并参与处理请求时被实例化的类,你可以在web.configttp Module>看到预定义的http Module 包括会话,验证等。 

 

最后,预祝你也能“抱得美人归”。

 

1《[翻译]了解ASP.NET底层架构.doc》:我可以毫不掩饰的向你表达我对这篇文章的喜爱,我就是反反复复看这篇文章,并且以这篇文章为中心,去看其它的资料,才把ASP.NET底层弄个明白的。

2 http://www.jdon.com/designpatterns/designpattern_factory.htm 《设计模式——工厂模式》:我在之前也没有接触过设计模式。但实际上,就如李建忠所说,看懂设计模式不难,但是要真正掌握设计模式,正确运用设计模式就难了。在ASP.NET底层架构中,多处用到工厂模式,看完这篇浅显易懂的介绍,你应该能够看懂工厂模式,这对于我们理解ASP.NET底层架构已经足够了。

3    http://www.netbei.com/Article/zz7/IIS/200508/3916_2.html,《彻底掌握IIS6.0功能及应用详解》对于你理解IIS6.0是相当有帮助的。不过你不必对这篇文章看得很细,你只要能够理解《[翻译]了解ASP.NET底层架构.doc》涉及到的部分已经足以。

    4《asp-net framework深度历险.pdf》这份文档对于你理解http modulehttp handler是相当有帮助的。但是,其在描述请求的处理顺序是不合理的,不能简单的把处理过程理解为一条单线的流程。

5  http://www.mikecat.net/blogview.asp?logID=1618

   http://www.cnblogs.com/Heroman/category/13774.html:这两个网址上对Asp.net2.0运行原理都讲得比较好。

6 http://msdn2.microsoft.com/en-us/library/ms227435.aspx:还有什么比MSDN更权威的呢?谢谢qinghu的推荐!!!

发布于 由 ozheric3 篇评论

读《.net框架程序设计》体会(二)-----“行者无疆”

     在我看《.net框架程序设计》的《文本处理》开始的时候,我发现我很快就被一些零零碎碎地概念所包围。这一块对我来说,着实比较陌生,读起来也比较吃力,到后来,索性翻翻,自我感觉一下,觉得没用就跳过。总之,这一章,我读得甚是马虎。

  一切似乎并没有什么不妥,并没有影响我后面章节的阅读。然而,我很快就犯错了。

  那时新人培训的时候,到后来我们做了一个petshop的模拟项目。由于要动态构造查询字符串,所以要用到StringBuilder,使用StringBuilder的Append或者是AppendFormat方法,然而,由于看书的时候,我并没有领会到这两者的差别,而且在使用这两个方法的时候也过于粗心,结果犯了个大错。后来,回头认真把书看了一下,觉悟之后是后悔,后悔当初没有仔细看。

    然而,一个人犯一次错,似乎不足以引起警觉。在一个地方摔倒,他会为自己寻找借口。于是他第二次,第三次......第n次犯同样的错误。我就是这样的人。同样是《.net框架程序设计》,在看到后面《CLR寄宿,应用程序域,反射》的时候,我再一次被那些概念所吓倒,再一次蜻蜓点水般掠过这些章节,并且为自己找了一个很容易安慰自己的理由:“这些概念很抽象,自己现在缺乏经验....”,再一次的放过了自己,于是我再一次发现自己“犯了个大错”:这几天,我在看asp.net底层机制的时候,比如httpruntime,httpapplication这些东西的时候,我又不得不重新去看《CLR寄宿,应用程序域,反射》。

    想起余世维的一句话:“你忘记的东西,你的对手会告诉你。”记得当时听到这句话的时候,很有感想,以至于后来复习考试也好,编程学习也好,常常想起这句话,也衍生出了很多的说法:“你放过的知识点,你以后的困难,你以后的错误会告诉你它的价值。”“你不去做的事,你的对手会去做,将来,他会告诉你怎么做。”一个想成为一名好的程序员的人,他是不会去害怕他面前成堆的概念的,他是不会害怕那一节又一节的知识点的,他是不会去害怕那厚厚的书本的。他是能够冷静的分析,细致的思考,直到他将问题弄个透彻的。就像一个行者,他会不断的向前跨步,不论前方是高山荒漠,还是泥泞沼泽,因为他追求的是远方........  

   

发布于 由 ozheric0 篇评论

(“面向对象”VS“基于对象”)&&(“句柄”VS“指针”)

      以前碰到介绍javascript的文章,第一句往往是:“JavaScript语言是基于对象的(Object-Based)的一门语言.....”。一直不明白,基于对象是什么概念。到网上搜搜,只是说“基于对象”没有提供“面向对象”语言那些继承,重载,多态等等的功能,大多都给出一个模糊的概念,没有直接对这个概念进行定义。

      近日,看《UML-面向对象设计基础》这本书,在这本书的第一章习题中提到了下面这样一个事实,读罢,才明白基于对象是怎么回事:

     “Peter Wegner在一篇顶级论文中,将环境划分为对象结构(objected-structured)、基于对象(object—based)、基于类(object—class)和面向对象(obJect—oriented)几个范畴。第一个范畴只具有封装和状态保持特性;第二个范畴增加了对象标识特性:第三个范畴增加了类的概念;最后一个范畴增加了继承和本章提到的其它特性......”

     “对象结构”,其实就是指对象把属性和方法封装了在一起,而“状态保持”是说,在对象的属性中保存着值(也就是对象的状态),这些值不会因为对象的某次使用完之后就丢失,下次使用还可以得到这些值(想想,在面向过程的函数中,一个函数使用完毕后,除了返回值,其他的都随之丢失了)。而对象的“标识特性”,就是指可以通过一个标识来指示这个对象,也就是“句柄”。

   对于“句柄”,也曾经令自己很是折恼了一番,记得当时新人培训的时候,还为这个问题着实讨论了很久。句柄,其实也不是个什么东西,它的引入就是为了可以用一个唯一的信息将对象与其它对象区分开来。比如,你实例化了某个类的两个对象,这就需要为每个对象分配一个唯一标识来区分它们,不错,可以使用“指针”,是的,在我们接触到的面向对象的环境中都是使用对象的物理内存地址(指针)作为这个唯一标识。但是,如果你需要在内存中移动对象或交换到硬盘(比如操作系统就需要干这些事)呢,使用指针就比较可怕了(这下,你可以理解为什么操作系统中没有使用指针,而是使用句柄来标识内核对象了吧)。所以,句柄最好是没有意义的,随机的并且是唯一的数字!!!当然,基于引入句柄的目的,我们还是可以简单将其理解为指针。

   呵呵,这下,再结合Peter Wegner的那段论述,应该能够明白“基于对象”是怎么回事了。Javascript自己没有太多的对象(有几个内置对象,比如string,date,math等),它的强大在于它把其它语言所创建的复杂对象统一起来,从而形成一个非常强大的对象系统。浏览器为javascript提供了丰富的接口,javascript基于这些接口大展其才,这才盛行天下。

发布于 由 ozheric0 篇评论

读《.net框架程序设计》体会(一)-----“物以类聚”

         由于qinghu的极力推荐,这么些日子以来,没事的时候,我就拿出那本《.net框架程序设计》来看。到现在,基本上,已经翻过一遍了。回头再翻翻,确有一番感触在心头,拿出这些感触来,和大家共享,也希望能够得到大家的指导。

       以前,在看一本讲述c#语法的小册子的时候,书上说,我们的程序设计其实就是对类型的设计。当时觉得很惊讶,我们那么多的眼花缭乱,纷繁负责的应用,岂是用一个“类”就可以搞定的?将信将疑的我拿这个问题去向qinghu请教,没想到,他语气十分肯定的说:“那当然啦!哪里还有类不能干的事?类中封装数据和方法,所有的应用不就是对数据的存取,对方法的调用吗?”当时听了他一番解释,觉得确实在理,但对这个观点还是缺乏感触,至少缺乏共鸣。

      然,看完《.net框架程序设计》,我的脑海中,确反反复复的浮现这个观念。尽管网上对这本书的评价是更多的是在讲述CLR原理(是的,尽管书名叫做《.net框架程序设计》,但这本书没有给你讲述.net Framework中的各种类库以及类中的各种方法,也就是说不是一本API方面的书,而是一本讲述运行机理的书,实际上,这本书的第二版就不叫做《.net 2.0框架程序设计》,而叫做《CLR 2.0》,讲述.net framework2.0下的CLR),我也认同这个观念,但是就我个人最深的体会确是作者围绕以类型设计为主体展开的叙述。除第一部分从宏观上讲述了.net框架的基本原理外,从第二部分开始,作者就着力在类型上:

      第二部分《类型与通用语言运行时》,主要讲述类型的基础知识,包括类型之间的转换,基本类型(值类型和引用类型)以及所有类型的基类型---system.object。

      第三部分,《类型设计》,讲述了类型中可以定义的内容,也就是类型成员,包括常数,字段,属性,方法,事件。 实际上,就我现在的认识来说,我认为属性和事件是不应该和字段和方法放在同一个级别上的,也就是说,类型成员应该来说,其实就是只有数据成员和方法成员。因为属性是只不过是方法上的“字段包装”。如果说,类封装了数据和操作,那么,属性就是在类的内部再定义一层封装,在这层封装,同样封装了字段和方法(说明:不一定是封装类中定义某一个字段,比如,在get方法中返回的是某几个字段的总和),编译过后,也确实就是方法(get和set)。而事件,实际上经过编译之后,实际上成了一个三个东西:一个字段(一个委托对象),两个方法(一个对委托对象注册事件处理程序,另一个则是注销。说明:这里仅只同步调用)。 当然,站在程序员的角度,说类型成员中包括常数,字段,属性,方法,事件更直接,因为我们确实是直接在类里面定义属性和事件。

      第四部分,则讲述了一些基本类型,包括string(还有stringBuilder),枚举,数组,接口,特性和委托。

      第五部分,则讲述了对类型的管理,异常处理和垃圾回收,当然还有反射等等。

     从编排体系上可以看出,作者始终围绕类型来讲,这也意味着,整个.net framework就是一大堆类型的堆砌。是的,.net的首要目的不就是提供给我们“一致的面向对象的编程模型”吗?面向对象编程不就是将int,string等等基本的数据类型,以及顺序,条件,循坏3种流程控制结构通过类型进行封装,然后,通过对类型的层层叠叠的组合,继承来实现对现实世界各种对象的模拟和抽象吗?

     呜呼,普天之下,莫非对象,而对象莫不以“类”聚。是故,当今“类”者,横行天下而无所顾忌也!

发布于 由 ozheric0 篇评论