Web服务器的消息流动阶段
当装载(hosting) ASP.NET 的 Web 服务器接收到 HTTP 请求时,HTTP 聆听程序 (HTTP Listener) 会将请求转交给 URL 指定的网站应用程序的工作流程 (Worker Process),ASP.NET 的工作流程处理器(aspnet_isapi.dll,若是 IIS 5.0 时则是 aspnet_wp.exe)会解析 URL,并启动位于 System.Web.Hosting 命名空间中的 ISAPIRuntime(视版本)对象,接收 HTTP 请求,并调用 HttpRuntime,运行 HttpRuntime.ProcessRequest(),在 ProcessRequest() 中使用 HttpApplicationFactory 创建新的 HttpApplication(或是指定的 IHttpHandler 处理器),再分派给 Page 中的 ProcessRequest() 或是 IHttpHandler 的 ProcessRequest() 方法,运行之后,再传回到 ISAPIRuntime,以及 aspnet_isapi.dll,最后交由 HTTP Listener 回传给客户端,因为运行程序有如管线般顺畅的运行,因此称为 HTTP Pipeline Mode。
在 ASP.NET 内部的 HTTP 处理器有:
ASP.NET网页中的事件程序
当 HttpWorkerRequest 调用 ASP.NET 网页(System.Web.UI 命名空间的 Page 类)的 Page.ProcessRequest() 方法时,它会依序的引发 Page 内的各个事件,并同时调用在 Page 中所有控件的相关事件,其引发顺序为:
如果 HttpWorkerRequest 调用的是实现 IHttpHandler 接口的 HTTP 处理程序 时,它只会调用 IHttpHandler.ProcessRequest() 方法,由它来处理程序的输出,不像 Page.ProcessRequest() 会处理事件顺序,因此 HTTP Handler 很适合轻量级的数据处理,像是输出文件数据流或是图片数据流等。
ASP.NET的事件模型
ASP.NET 的原始设计构想,就是要让开发人员能够像 VB 开发工具那样,可以使用事件驱动式程序开发模式 (Event-Driven Programming Model) 的方法来开发网页与应用程序,若要以ASP技术来做到这件事的话,用必须要使用大量的辅助信息,像是查询字符串或是窗体字段数据来识别与判断对象的来源、事件流向以及调用的函数等等,需要撰写的代码量相当的多,但 ASP.NET 很巧妙利用窗体字段和JavaScript脚本把事件的传递模型隐藏起来了。
ASP.NET 的事件模型是由 <form runat="server"></form> 以及数个 Hidden Field 组合而成,基于 HTTP 模型的限制,所有的网页程序在运行结果输出到客户端后,程序就会退出运行,为了维护在 ASP.NET 网页与控件的状态数据,因此在输出 ASP.NET 控件时,ASP.NET 会将部分状态数据存储到网页的 Hidden Field 中,这类型的状态数据称为 ViewState(ID 为 __VIEWSTATE),在服务器端即会被解译出状态与事件数据。在大多数的自带 Web 控件中都有使用到这个机制,因此在使用大量 ASP.NET Web 控件的网页中,会有许多的 ViewState 会存放在网页中并随着 HTTP 数据流输出到客户端,ViewState 在输出时,会被加密为一组乱码字符串,其金钥值定义在电脑中,并且每一个对象都会被串行化 (serialize) 成字符串(因此若是自定义对象要放到 ViewState 时,则应要让它支持串行化),再输出到 __VIEWSTATE 字段中,在每次的网页来回时都会被传输,较大的 ViewState 会让网页大小膨胀,不利于快速的网络传输,不过 ASP.NET 本身有提供将 ViewState 关闭的功能,因此如果控件不需要状态保存时,可将它关闭以减少输出的大小。
为确保控件的事件能够确实被引发,让事件驱动能够被运行,因此控件事件引发命令时需要的参数,是交由 JavaScript 脚本在客户端引发时,填入另一个 Hidden Field(ID 为 __EVENTTARGET 以及 __EVENTARGUMENT),并且引发窗体的提交指示 (submit),传送到服务端后,服务端的 HttpApplication 中的工具函数会解析 __EVENTTARGET 和 __EVENTARGUMENT 字段中的信息,并且交由控件所实现的 RaisePostBackEvent() 来引发事件,并由 .NET Framework 内部的事件处理机制接手处理(调用控件设置的事件处理程序)。
ASP.NET的来回模式
在 ASP.NET 运行的时候,经常会有网页的来回动作 (round-trip),在 ASP.NET 中称为 PostBack,在传统的 ASP 技术上,判断网页的来回是需要由开发人员自行撰写,到了 ASP.NET 时,开发人员可以用 Page.IsPostBack 机能来判断是否为第一次运行(当 ASP.NET 发现 HTTP POST 要求的数据是空值时),它可以保证 ASP.NET 的控件事件只会运行一次,但是它有个缺点(基于 HTTP POST 本身的缺陷),就是若用户使用浏览器的刷新功能(按 F5 或刷新的按钮)刷新网页时,最后一次运行的事件会再被运行一次,若要避免这个状况,必须要强迫浏览器清空高速缓存才可以。
ASP.NET 2.0 中有新增三个来回模式:
来回模式不仅是 ASP.NET 运作时的核心,它也是 ASP.NET 应用程序的一个主要缺点,尤其是在设计复杂度高的页面时,在网页中隐藏的 ViewState 的大小会相当大,而在每次的来回动作中,都会传送 ViewState 在内的窗体信息,大量的 ViewState 会使得传送的时间拉长,而且每次来回动作都会让整个网页被刷新,而出现闪烁的情况(就算在本地端也一样),但在AJAX技术尚未成熟时,只能够忍受这种因底层限制所带来的问题,在ASP.NET AJAX技术发展出来后,通过UpdatePanel成功的缓解了这个问题(但 ViewState 传送的问题仍然未根本的解决,必须要使用像 Page Method 这样的方式才能彻底的解决)。
脚本
ASP.NET 的 Web 控件有时会包装一些客户端脚本 (client-side scripting),在控件被绘制时输出到客户端,这些脚本多数被包装在 DLL 的资源档中,并由 ScriptResource.axd 处理程序来输出,开发人员也可以利用 ClientScriptManager(Page.ClientScript 属性)中的方法来添加脚本到网页程序中,常用的方法有:
基本对象
以往在 ASP 中常被使用的五大基本对象,在 ASP.NET 中仍然持续被支持,但它们都换了一个身份来提供:
延展性支持
除了 ASP.NET 网页以外,.NET Framework 还提供了两种可以由开发人员自行发展处理模型的模块,一种是HTTP Handler,另一种则是HTTP Module。
HTTP Handler(扩展名为 .ashx)由 System.Web.IHttpHandler 接口定义了必要的方法(可支持异步的 HTTP Handler 称为 HTTP Async Handler,由 System.Web.IHttpAsyncHandler 接口定义),其中最重要的方法是 ProcessRequest() 方法,开发人员必须要实现这个方法,才能够让 HTTP Handler 有作用,它也可以通过 ASP.NET 的组态设置,让 HTTP Handler 可以处理特定的扩展名,它可以被视为 .NET Framework 中的 ISAPI Extensions 实现方法。
HTTP Module 则是由 System.Web.IHttpModule 接口定义,它可以在整个网页生命周期中被调用多次,并实际处理由 HttpApplication 所引发的事件,开发人员需要实现 IHttpModule.Init() 方法,以及处理 HttpApplication 事件需要的代码。它可被视为 .NET Framework 中的 ISAPI Filter 实现方法。