ASP.NET处理架构

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 处理器有:

  • ISAPIRuntime:由 aspnet_isapi.dll 调用,初始化 HttpWorkerRequest 对象(会由IIS的版本决定要初始化的版本)。
  • HttpRuntime:提供请求队列 (Request Queue)、调用 HttpWorkerRequest 中的 ProcessRequest() 方法,以及后续的处理工作。
  • HttpWorkerRequest:产生 HttpApplication、HttpRequest、HttpResponse 等基础对象的 HTTP 请求对象,并将要求转送到要处理的对象(并调用它的 ProcessRequest() 方法)。
  • IHttpHandler 与 IHttpAsyncHandler:负责处理 HTTP 请求的单元,由 ProcessRequest() 来分派与运行请求。

ASP.NET网页中的事件程序

当 HttpWorkerRequest 调用 ASP.NET 网页(System.Web.UI 命名空间的 Page 类)的 Page.ProcessRequest() 方法时,它会依序的引发 Page 内的各个事件,并同时调用在 Page 中所有控件的相关事件,其引发顺序为:

  • PreInit 事件:运行预先初始化的工作,在ASP.NET 2.0中,若要动态调整主版页面 (Master Page)、主题 (Theme) 时,要在这个事件中调整。
  • Init 事件:运行初始化工作。
  • InitCompleted 事件:在完成初始化工作后引发。
  • Preload 事件:运行预先加载的工作。
  • Load 事件:运行加载的工作,大多数的网页都拥有 Page_Load 事件处理程序,用户控件 (user control) 中也有 Page_Load 事件例程,都会在此时调用。
  • 控件的 PostBack 变更通知:当网页侦测到是 PostBack 要求时,会引发 PostBack 消息通知的事件。
  • 控件的 PostBack 相关事件:当网页侦测到是 PostBack 要求时,会引发 PostBack 消息指定的控件的事件。
  • LoadCompleted 事件:运行加载完成后的工作。
  • PreRender 事件:处理在产生 HTML 结果前的工作。
  • SaveStateCompleted 事件:处理页面状态(ViewState 与 ControlState)存储完成后的事件。
  • Render 事件:处理产生 HTML 的工作。
  • Unload 事件:处理退出网页处理时的工作。

如果 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 中有新增三个来回模式:

  • Cross Page Postback:允许跨不同的网页运行 PostBack,服务端可使用 Page.IsCrossPostBack 来判断是否是跨网页型的来回。
  • Async Page Mode:允许网页使用异步的方式运行,服务端可用 Page.IsAsync 来判断。
  • Callback:ASP.NET 2.0 新增的由网页回呼客户端指令的功能,服务端可用 Page.IsCallback 来判断是否要求是来自 Callback。

来回模式不仅是 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 属性)中的方法来添加脚本到网页程序中,常用的方法有:

  • ClientScriptManager.RegisterClientScriptBlock():注册客户端脚本区块 (script block)。
  • ClientScriptManager.RegisterStartupScript():注册在起始时运行的脚本。
  • ClientScriptManager.RegisterOnSubmitStatement():注册在处理窗体发送时要运行的脚本。
  • ClientScriptManager.RegisterClientScriptInclude():注册由外部文件 (.js) 提供的脚本来源。

基本对象

以往在 ASP 中常被使用的五大基本对象,在 ASP.NET 中仍然持续被支持,但它们都换了一个身份来提供:

  • Application:包装了 HttpApplication 对象,在程序中使用 Application 指令取得的对象,都是来自于 HttpContext.Current.Application 属性回传而得。
  • Request:包装了 HttpRequest 对象,在程序中使用 Request 指令取得的对象,都是来自于 HttpContext.Current.Request 属性回传而得。
  • Response:包装了 HttpResponse 对象,在程序中使用 Response 指令取得的对象,都是来自于 HttpContext.Current.Response 属性回传而得。
  • Session:包装了 HttpSessionState 对象,在程序中使用 Session 指令取得的对象,都是来自于 HttpContext.Current.Session 属性回传而得。
  • Server:包装了 HttpServerUtility 对象,在程序中使用 Server 指令取得的对象,都是来自于 HttpContext.Current.Server 属性回传而得。

延展性支持

除了 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 实现方法。

你可能感兴趣的:(服务器,网站,应用程序,空间,处理器)