當一個客戶端頁面訪問IIS試圖獲取一些信息的時候
發生了什麼事情?一個請求在通過了HTTP管道後又發生了什麼?本文主要是描述這兩個過程
即IIS處理請求和的頁面生命周期
歡迎大家積極拍磚
共同學習
共同進步
首先我們要弄清楚兩個非常重要的概念
worker process(w
wp
exe)
worker process管理所有的來自客戶端的請求並給出響應
它是IIS下應用程序的核心
application pool
它是worker process的容器
IIS
及之前的IIS版本均沒有application pool的概念
每一個application pool對應著一個worker process
在IIS Metabase中維護著Application Pool和worker process的Mapping
這就避免了IIS
中出現的worker process(IIS
中是aspnet_wp
exe
同一時間只能運行一個該進程)崩潰
application全崩潰的局面
客戶端向IIS發出一個資源請求後發生了如下事情
server接受該請求
IIS
通過內核模式(Kernel mode)中的HTTP
SYS來分發各個Request到application pool
這並不是隨機的過程
在application pool創建的時候就已經注冊到了HTTP
SYS
所以當請求來到時HTTP
SYS會直接發送到相應的application pool
接下來在IIS的用戶模式(User mode)中
Web Admin Services (WAS) 做了從HTTP
SYS中得到Request並分發到application pool的工作
application pool直接把request傳遞給worker process
請求傳遞到worker process後worker process初始化加載ASP
NET ISAPI(Internet Server Application Program Interface)
ASP
NET ISAPI進而加載CLR創建托管環境
(注
ISAPI只是一個接口
起到一個代理的作用
主要能力就是根據Request URL的後綴來尋找該後綴的處理程序)
ASP
NET ISAPI定義在aspnet_isapi
dll中
它本身運行在一個非托管的環境中
ASP
NET ISAPI開始一個HttpRuntime
HttpRuntime調用ProcessRequest方法來開始處理請求
ProcessRequest根據ISAPI傳進來的iWRType 來創建不同的HttpWorkerRequest
從而屏蔽了不同IIS的差異
接下來ProcessRequest方法創建了HttpContext
我們使用HTTPContext
Current來訪問它
在HttpRuntime使用HttpApplicationFactory創建了HttpApplication對象(IHttpHandler)以後
所有的請求都會在通過httpmodule後找到相應的Httphandler進行處理
在HttpApplicationFactory創建HttpApplication之前
會查找config(nfig和nfig)文件中注冊的所有的HttpModule
並根據配置信息加載相應的Assembly
通過Reflection創建對應的HttpModule
並將這些Module加到HttpApplication 的_moduleCollection Filed中
我們對一個Application的請求最終會落到一個HttpApplication對象上
當一個請求到來時
ASP
NET會在Httplication Pool中查找未被使用的HttpApplication對象
請求通過HTTP管道後每個請求都發向相關的各自的httphandler
IIS請求處理過程結束
HttpHandler是HTTP管道的終點
它為每個request生成輸出
System
Web
UI
Page就是這樣一個典型的Httphandler
當我們請求一個aspx頁面
這個HttpHandler就生成html發送回客戶端
看Page類的簽名
public class Page : TemplateControl
IHttpHandler
{
}
可以看到
Page類就是一個HttpHandler
綜上整個過程就是
當客戶端向服務器發送資源請求時
請求首先到達IIS的HTTP
SYS
然後HTTP
SYS發送請求道對應的Application Pool
然後Application Pool發送請求到Worker Process(W
WP
exe)中加載ISAPI Extension
ISAPI創建一個HttpRuntime對象來通過HttpModule和HttpHandler處理請求
然後頁面生命周期就開始了
頁面生命周期開始
頁面生命周期的主要階段包括
頁面初始化(Init): 服務器創建服務器控件的實例
加載(load): 控件實例被加載到它定義的頁面對象中
預輸出:(PreRender) 對控件的更改被更新
准備輸出
保存(SaveViewState): 控件的狀態信息被保存
輸出頁面(Render):服務器為控件創建html標記
處理(Dispose): 主要做的工作就是dispose
關閉數據庫連接
文件資源的釋放等
卸載(Unload)
銷毀服務器控件的實例
頁面生命周期的主要事件
PreInit:
檢查IsPostBack 屬性
動態設置Master Page
動態設置Theme
設置控件的默認值(UniqueId等)
重新創建動態控件(初始化控件)
初始化控件的值
Init: 這個事件發生在所有的控件被初始化
所有的皮膚設置被應用以後
它用來讀取或者初始化控件屬性
它能夠用來注冊一些aspx頁面中沒有指出的控件的事件
InitComplete: Use this event for processing tasks that require all initialization to be complete
PreLoad: 加載頁面的ViewState和所有的控件
然後處理所有的包含在Request實例中的postback數據
Load: 這個事件可能是大家最熟悉的了
需要注意的是
Page對象會遞歸的調用子控件的onload事件直到頁面和所有的子控件被加載完成
這個事件主要用來設置控件屬性的值
建立數據庫連接(通常不這麼做)
Control events: 這個就不多說了
主要是處理控件的事件
例如click
這也就讓我們明白了每次我們click一個Button的時候
實際上是要先去執行load事件然後才執行click事件的
一般我們用!IsPostBack來判斷一下從而避免執行不必要的加載邏輯
LoadComplete: 頁面所有的控件都被加載以後執行
暫時沒有想到用來干什麼
PreRender: 在HTML被生成之前這是最後一個事件
每一個頁面中的控件都有PreRender的過程
在這裡對將要輸出的HTML結果進行最後一次修改
SaveStateComplete: 在這個時間發生之前
已經保存了所有控件和頁面的
任何對page或者控件的改動都不會產生左右
暫時沒想到用來干啥
Render: 它不是一個事件而是一個方法
工作就是把HTML寫回客戶端浏覽器
UnLoad: 頁面中的每一個控件都會發生這件事
在控件中
使用這個事件來做清理工作
例如關閉數據庫連接等
對與頁面本身也是做清理工作
例如關閉打開的文件和數據庫連接
或者結束日志或者其它指定的工作
需要說明的是
每次Request都會創建一個全新的Page類的實例
所以在頁面中的自己定義的字段是不能在兩次request中傳遞值的
需要使用viewstate來存儲
HttpHandler根據頁面生命周期中事件的處理把結果發回IISIIS再把結果發回客戶端浏覽器
值得注意的是
在這個過程中請求會再次通過HttpModule(注冊一個EndRequest事件)
至此
整個Request結束
From:http://tw.wingwit.com/Article/program/net/201311/11446.html