asp.net 管道事件註冊、管道執行步驟模擬
前一篇文章我們學習了WebForm開發中頁面級事件的註冊,今天我們就接著學習另外一種請求過濾機制:管道事件註冊
我們知道Application的管道有23個步驟 19個事件
在進一步講解之前,我們先來了解一下19個管道事件
(1)BeginRequest: 開始處理請求
(2)AuthenticateRequest授權驗證請求,獲取使用者授權資訊
(3):PostAuthenticateRequest獲取成功
(4): AunthorizeRequest 授權,一般來檢查使用者是否獲得許可權
(5):PostAuthorizeRequest:獲得授權
(6):ResolveRequestCache:獲取頁面快取結果
(7):PostResolveRequestCache 已獲取快取 當前請求對映到MvcHandler(pr): 建立控制器工廠 ,建立控制器,呼叫action執行,view→response//action Handler : PR()
(8):PostMapRequestHandler 建立頁面物件:建立 最終處理當前http請求的 Handler 例項: 第一從HttpContext中獲取當前的PR Handler ,Create
(9):PostAcquireRequestState 獲取Session
(10)PostAcquireRequestState 獲得Session
(11)PreRequestHandlerExecute:準備執行頁面物件 執行頁面物件的ProcessRequest方法
(12)PostRequestHandlerExecute 執行完頁面物件了
(13)ReleaseRequestState 釋放請求狀態
(14)PostReleaseRequestState 已釋放請求狀態
(15)UpdateRequestCache 更新快取
(16)PostUpdateRequestCache 已更新快取
(17)LogRequest 日誌記錄
(18)PostLogRequest 已完成日誌
(19)EndRequest 完成
這些事件都是可以對請求報文進行處理的,也就是說可以進行過濾操作的。預設的很多事件都是沒有註冊的,管道流通到這個地方的時候什麼都不會執行。但是我們可以通過手動註冊管道事件(其實就是給某個事件內部新增程式碼),實現請求的過濾。
那具體應該怎麼操作呢?總的來說有兩種方法,下面我們來一一學習。
1.通過Global.asax檔案操作
通過asp.net 的原理我們知道,HttpApplication在物件池中不存在的時候就是通過反射該檔案來建立Application物件的,它和Application物件是密切相關的。我們當然也就可以在這個類裡面進行管道的事件註冊。
該類預設已經為我們註冊了下面的一系列事件(但是事件裡面都是沒有具體實現程式碼的)
protected void Application_BeginRequest(object sender, EventArgs e)
{
}
protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
}
在開始我們自己管道事件的註冊之前,我們不妨對上面的事件觀察一下。
觀察上面的命名規則,我們看到方法的名稱都是以Application開頭。通過上一篇頁面級事件註冊的學習已經知道, 如果我們想註冊管道事件也需要這樣操作(預設的已經幫我們把事件與方法關聯起來了)
註冊管道事件程式碼如下所示:
protected void Application_BeginRequest(object sender, EventArgs e)
{
Context.Response.Write("開始處理請求。。。。。。");
}
protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
Context.Response.Write("驗證請求。。。。。。");
}
protected void Application_PostAuthenticateRequest(object sender, EventArgs e)
{
Context.Response.Write("獲取成功");
}
protected void Application_EndRequest(object sender, EventArgs e)
{
Context.Response.Write("結束請求");
}
執行程式
到請求執行到管道所在的事件的時候就會執行我們在管道里面編寫的程式碼。
2.定義管道類
(1)定義一個類HttpModule 需要實現IHttpModule介面
IHttpModule:IHttpModule介面中也沒什麼東西,最重要的就是一個Init方法,通過該方法實現事件的註冊。 定義HttpModule類,實現上面的介面。
public class HttpModule:IHttpModule
{
public void Dispose()
{
throw new NotImplementedException();
}
//注意 這裡傳遞的是HttpApplication物件
public void Init(HttpApplication context)
{
// throw new NotImplementedException();
context.BeginRequest += new EventHandler(BeginRequest);//關鍵點 就是在這裡註冊事件的
}
public void BeginRequest(object sender, EventArgs e)
{
var context = (sender as HttpApplication).Context;
context.Response.Write("這是開始執行請求的事件");
}
}
同第一種Global方法不同的是, 這種方法需要在建立的類的Init()方法中顯示繫結事件和方法。
<2>配置Web.config
程式執行的時候會讀取配置資訊,我們可以在配置裡面新增內容來告訴應用程式一些資訊。
在Web.config配置檔案中新增管道節點,如下所示
<httpModules>
<add name="HttpModule" type="WebApplication1.HttpModule"/>--一定要是全名稱(名稱空間+類名)
</httpModules>
我們可以新增多個管道 (其實感覺這沒必要,因為我們完全可以在一個管道的Init()方法中註冊多個事件),不需要的話直接註釋掉就可以了,這裡也是體現了管道很好的外掛機制。
到這裡,不知道你有沒有疑問產生。第一種方法,我們之所以可以在Global.asax檔案中註冊管道是因為我們建立HttpApplication物件的時候會根據Global檔案反射出一個例項出來。那麼,我們第二種方式又是在哪裡體現我們確實是實現了管道事件的註冊呢?
其實,通過ApplicationFactory建立的Application 物件,在建立完Application之後會呼叫Application物件的初始化方法。在Application的初始化內部會讀取配置檔案,讀取所有的HttpModule並放到一個ModuleCollection管道集合中去,最後迴圈遍歷這個集合中每個管道的Init()方法,這樣就完成了所有管道事件的註冊。注意,這裡只是完成了管道事件的註冊。
Ok,執行程式,看看效果
OK,兩種管道事件的註冊方法講解完畢。
下面我們模擬一下管道的執行,加深對管道的瞭解。
通過對asp.net原理的瞭解,我們知道請求交給HttpRuntime之後,會呼叫HttpRuntime的ProcessRequest()方法,那在該方法的內部具體執行了什麼呢?
下面的程式碼對這個過程進行了大致模擬。
定義HttpApplication類
對上面的程式碼做個總結:
IsapiRuntime.dll會呼叫它的ProcessRequest()方法,這個方法內有一個ecb控制代碼(存放著請求報文的內容)。在這個方法內部,會根據這個控制代碼建立一個HttpWorkRequest物件。HttpRutime的ProcssRequest()方法會以上面建立的HttpWorkRequest物件為引數,建立HttpContext。接著會根據HttpApplication或Global.cs檔案創建出一個HttpApplication物件並進行HttpApplication物件的初始化操作(在這個初始化操作過程中會讀取配置檔案,也就是上面第二種管道事件註冊的核心思想)。接著再執行HttpApplication物件的ProcessRequest()方法,在這個方法的內部會進行管道事件的執行以及aspx請求頁面宣告週期的執行。
Ok,asp.net 的管道流通大概就是這樣,不知道講解的夠不夠請求,如果你對asp.net原理有疑問,歡迎參考我的另一篇文章:asp.net 的原理