天天看點

Asp.Net 構架(HttpModule 介紹) - Part.3來自HttpModule的處理,請求結束

導讀:

  PDF 浏覽:http://www.tracefact.net/Document/Introduction-to-Http-Module.pdf

   Asp.Net 構架(HttpModule 介紹) - Part.3

   引言

  Http 請求處理流程和 Http Handler 介紹這兩篇文章裡,我們首先了解了Http請求在伺服器端的處理流程,随後我們知道Http請求最終會由實作了IHttpHandler接口的類進行處理(應該記得Page類實作了IHttpHandler)。從 Http 請求處理流程一文的最後的一幅圖中可以看到,在Http請求由IHttpHandler處理之前,它需要通過一系列的Http Module;在請求處理之後,它需要再次通過一系列的Http Module,那麼這些Http Module是如何組成的?用來做什麼呢?本文将對Http Module作以介紹。

   Http Module概述

  暫時先不考慮我們自己實作Http Module的情況。在.Net中,Http Module 是實作了IHttpModule接口的程式集。IHttpModule 接口本身并沒有什麼好大寫特寫的,由它的名字可以看出,它不過是一個普普通通的接口而已。實際上,我們關心的是實作了這些接口的類,如果我們也編寫代碼實作了這個接口,那麼有什麼用途。一般來說,我們可以将Asp.Net中的事件分成三個級别,最頂層是 應用程式級事件、其次是頁面級事件、最下面是控件級事件,事件的觸發分别與 應用程式周期、頁面周期、控件周期緊密相關。 而 Http Module 的作用是與應用程式事件 密切相關的。

  我們通過Http Module在Http請求管道(Pipeline)中注冊期望對應用程式事件做出反應的方法,在相應的事件觸發的時候(比如說BeginRequest事件,它在應用程式收到一個Http請求并即将對其進行處理時觸發),便會調用Http Module注冊了的方法,實際的工作在這些方法中執行。.Net 本身已經有很多的Http Module,其中包括 表單驗證Module(FormsAuthenticationModule), Session 狀态Module(SessionStateModule),輸出緩存Module (OutputCacheModule)等。

   注冊 Http Module

  在注冊我們自己編寫的 Http Module 之前,先來看看Asp.Net中已經有的HttpModule。與 Http Handler類似,我們需要打開機器上C:/WINDOWS/Microsoft.NET/Framework/ v2.0.50727/CONFIG 目錄下的 web.config 檔案。找到 結點,應該可以看到下面的内容:

  

  

  

  

  

  

  

  

  ... 略

  

  我們先從結點上看,type屬性與上一節所說的http handler結點的type屬性類似,都代表了相應的程式集。但是,與http handler 不同,module隻提供了一個name屬性,沒有諸如 path這樣指定某一特定(或者用通配符 * 代表某一種類)檔案的處理程式。這是與Module的特點相關的,我們知道 module 是響應應用程式周期中觸發的事件,對于所有送出到aspnet_isapi.dll的請求都一樣,即便請求隻是像類似http://www.tracefact.net/images/logo.gif 這樣擷取一張圖檔而已(對ISAPI進行過設定以後,預設aspnet_isapi.dll不接手圖檔檔案)。

  與Http handler類似,在這冊我們自己的http module 時,假設類名為ModuleDemo,位于myNameSpace命名空間下,程式集名稱為myDll,我們隻需将myDll.dll拷貝到Bin目錄下,并在站點的 web.config 檔案 system.web 結點下建立 httpModules 結點:

  

  

  

  

  

  type屬性由分号“,”分為兩部分,前面是命名空間及類名,也就是類型名;後面是程式集名。如果我們将代碼建立在App_Code目錄中,則不需要再指定程式集名。

  name屬性由我們自己命名,不一定與類名相同,此處我将它命名為“CustomModuleName”。我們可以通過應用程式(HttpApplication)的Modules屬性擷取HttpModuleCollection集合,然後通過name屬性,進一步擷取HttpModule對象。

  通過name屬性,我們還可以在global.asax中檔案中編寫自定義HttpModule暴露出的事件的處理程式,它采用的格式是:void ModuleName_EventName(object sender, EventArgs e)。我們将在後面做更詳細介紹。

   Asp.Net 内置的 Http Modules

  下面這張表格列出了C:/WINDOWS/Microsoft.NET/Framework/ v2.0.50727/CONFIG下的Web.Config中的 Asp.Net 内置的Http Modules 及其主要作用。

   名稱 類型 功能

  OutputCache System.Web.Caching.OutputCacheModule 頁面級輸出緩存

  Session System.Web.SessionState.SessionStateModule Session狀态管理

  WindowsAuthentication System.Web.Security.WindowsAuthenticationModule 用內建Windows身份驗證進行用戶端驗證

  FormsAuthentication System.Web.Security.FormsAuthenticationModule 用基于Cookie的窗體身份驗證進行用戶端身份驗證

  PassportAuthentication System.Web.Security.PassportAuthenticationModule 用MS護照進行客戶身份驗證

  RoleManager System.Web.Security.RoleManagerModule 管理目前使用者角色

  UrlAuthorization System.Web.Security.UrlAuthorizationModule 判斷使用者是否被授權通路某一URL

  FileAuthorization System.Web.Security.FileAuthorizationModule 判斷使用者是否被授權通路某一資源

  AnonymousIdentification System.Web.Security.AnonymousIdentificationModule 管理Asp.Net應用程式中的匿名通路

  Profile System.Web.Profile.ProfileModule 管理使用者檔案檔案的創立 及相關事件

  ErrorHandlerModule System.Web.Mobile.ErrorHandlerModule 捕捉異常,格式化錯誤提示字元,傳遞給用戶端程式

  我們将在後面用程式設計的方式來檢視它。

   IHttpModule接口

  看了這麼多理論知識,本節将開始動手寫點程式,實作自己的Http Module。我們首先需要看下IHttpModule 接口,它包括下面兩個方法:

  public void Init(HttpApplication context);

  public void Dispose();

   Init():這個方法接受一個HttpApplication對象,HttpApplication代表了目前的應用程式,我們需要在這個方法内注冊 HttpApplication對象暴露給用戶端的事件。可見,這個方法僅僅是用來對事件進行注冊,而實際的事件處理程式,需要我們另外寫方法。

  整個過程很好了解:

  當站點第一個資源被通路的時候,Asp.Net會建立HttpApplication類的執行個體,它代表着站點應用程式,同時會建立所有在Web.Config中注冊過的Module執行個體。

  在建立Module執行個體的時候會調用Module的Init()方法。

  在Init()方法内,對想要作出響應的HttpApplication暴露出的事件進行注冊。(僅僅進行方法的簡單注冊,實際的方法需要另寫)。

  HttpApplication在其應用程式周期中觸發各類事件。

  觸發事件的時候調用Module在其Init()方法中注冊過的方法。

   NOTE:如果你不了解事件注冊等相關内容,請參閱 C#中的委托與事件一文。

   Dispose():它可以在進行垃圾回收之前進行一些清理工作。

  綜上所述:實作一個 IHttpModule 的模闆一般是這樣的:

  public class ModuleDemo:IHttpModule

  {

  public void Init(HttpApplication context) {

  // 注冊HttpApplication應用程式 BeginRequest 事件

  // 也可以是其他任何HttpApplication暴露出的事件

  context.BeginRequest += new EventHandler(context_BeginRequest);

  }

  void context_BeginRequest(object sender, EventArgs e) {

  HttpApplication application = (HttpApplication)sender;

  HttpContext context = application.Context;

  // 做些實際的工作,HttpContext對象都獲得了,剩下的基本可以自由發揮了

  }

  public void Dispose() {

  }

  }

   通過Http Module向Http請求輸出流中寫入文字

  本例中,我們僅用BeginRequest事件和 EndRequest 事件對 Http Module 的使用作以說明。我們通過這個範例,了解 Http Module 基本的使用方法。

  首先,請建立一個新的站點,在App_Code目錄中添加類檔案: ModuleDemo.cs:

  public class ModuleDemo:IHttpModule

  {

  // Init方法僅用于給期望的事件注冊方法

  public void Init(HttpApplication context) {

  context.BeginRequest += new EventHandler(context_BeginRequest);

  context.EndRequest += new EventHandler(context_EndRequest);

  }

  // 處理BeginRequest 事件的實際代碼

  void context_BeginRequest(object sender, EventArgs e) {

  HttpApplication application = (HttpApplication)sender;

  HttpContext context = application.Context;

  context.Response.Write("

來自HttpModule的處理,請求結束

");

  }

  

  public void Dispose() {

  }

  }

  上面的代碼很簡單,它注冊了 HttpApplication執行個體的 BeginRequest 事件 和 EndRequest事件,事件處理方法的作用僅僅是在http請求開始和結束的時候,給http請求的輸入流中分别寫入不同的内容。

  接下來在 Web.config 的 System.web 結點中寫入以下内容:

  

  

  

  

  

  然後,打開建立站點時自動建立的 Default.aspx檔案,在裡面打幾個字,為了做區分,我輸入的是:位于.aspx頁面上的文字。然後,我們在浏覽器中打開它,應該會看到像這樣:

  

Asp.Net 構架(HttpModule 介紹) - Part.3來自HttpModule的處理,請求結束

  

  然後我們再建立一個 Default2.aspx,在浏覽器中浏覽,可以看到,兩個頁面的效果相同。這說明對于不同的兩個檔案,http Module都起了作用,可見它确實是位于應用程式級,而非頁面級。

  現在,我們再打開站點中的一張圖檔檔案,發現顯示出的是一個紅叉叉,為什呢?因為Http Module 針對是http 請求,而不是某個或某一類檔案,是以當請求一張圖檔的時候,我們編寫的http Module依然會起作用,将文字插入到二進制圖檔中,破壞了檔案格式,自然隻能顯示紅叉叉了。

   NOTE:如果你發現你的圖檔顯示正常,請不要驚訝,事情是這樣的:回想一下第一節我們讨論到的,對于圖檔檔案,由IIS直接處理,并不會交由aspnet_isapi.dll,是以,Module無法捕獲對于圖檔類型檔案的請求。解決方法就是在IIS中進行設定一下。

  這裡需要提請注意的是:如果你使用Vs2005自帶的Local Server,那麼你無需對IIS進行設定,所有的不論圖檔還是任何檔案類型,都會交由aspnet_isapi.dll處理。

   周遊Http Module集合

  現在,我們通過周遊 HttpModuleCollection 集合來檢視注冊給應用程式的所有 Http Module 的名稱。

  建立一個檔案 RegisteredModules.aspx,在代碼後置檔案中添加如下方法:

  private string ShowModules() {

  HttpApplication app = Context.ApplicationInstance; //擷取目前上下文的HttpApplication環境

  HttpModuleCollection moduleCollection = app.Modules; //擷取所有Module集合

  // 擷取所有的 Module 名稱

  string[] moduleNames = moduleCollection.AllKeys;

  System.Text.StringBuilder results = new System.Text.StringBuilder(); //周遊結果集

  foreach (string name in moduleNames) {

  // 獲得Module名稱

  results.Append("

名稱:" + name + "

");

  // 獲得Module類型

  results.Append("類型:" + moduleCollection[name].ToString() + "

");

  }

  return results.ToString();

  }

  然後在Page_Load方法中輸出一下:

  protected void Page_Load(object sender, EventArgs e)

  {

  Response.Write(ShowModules());

  }

  我們應該可以看到下面這樣的畫面:

  

Asp.Net 構架(HttpModule 介紹) - Part.3來自HttpModule的處理,請求結束

  

  與之前列出的那張表格比較一下,可以看出是幾乎完全一緻的(多了一個DefaultAuthentication)。另外注意上圖的倒數第四行,那不是我們自己定義的Module麼?name為MyModule,類型為ModuleDemo。

   Global.asax檔案與 Http Module

  早在asp時代,大家就知道這個檔案了。它主要用于放置對于 應用程式事件或者 Session事件的響應程式。大家熟悉的有Application_Start、Application_End、Session_Start、Session_End 等。

  在asp.net中,Glabal不僅可以注冊應用程式和Session事件,還可以注冊Http Module暴露出的事件;不僅可以注冊系統Module的事件,也可以注冊我們自己義的Module暴露出的事件。在具體介紹之前,這裡需要首先注意兩點:

  在每處理一個Http請求時,應用程式事件都會觸發一遍,但是Application_Start和 Application_End 例外,它僅在第一個資源檔案被通路時被觸發。

  Http Module無法注冊和響應Session事件,對于Session_Start 和 Session_End,隻能通過Glabal.asax來處理。

  好了,我們現在修改之前 ModuleDemo 範例程式,給它像下面這樣給它添加一個事件(為了使程式簡潔一些,我做了簡化):

  public class ModuleDemo : IHttpModule {

  // 聲明一個事件

  public event EventHandler ExposedEvent;

  // Init方法僅用于給期望的事件注冊方法

  public void Init(HttpApplication context) {

  context.BeginRequest += new EventHandler(context_BeginRequest);

  }

  // 處理BeginRequest 事件的實際代碼

  void context_BeginRequest(object sender, EventArgs e) {

  HttpApplication application = (HttpApplication)sender;

  HttpContext context = application.Context;

  context.Response.Write("

來自 Global.asax 的文字

");

  }

  現在,我們打開之前的頁面,應該可以見到這樣,可見,我們成功的将 Glabal.asax檔案與我們自己定義的Http Module所暴露出的事件 ExposedEvent 聯系到了一起:

  

Asp.Net 構架(HttpModule 介紹) - Part.3來自HttpModule的處理,請求結束

  

   總結

  本文簡單地介紹了什麼是Http Module。我們首先了解了Http Module的作用,然後檢視了Asp.Net 内置的Module,接着我們介紹了IHttpModule接口,并通過了一個簡單的範例實作了此接口,最後我們讨論了 Http Module與 Global.asax 檔案的聯系。

  本文僅僅是對IHttpModule作以簡單介紹,對其更多的實際應用,會在後續文章中補充。

  希望這篇文章能給你帶來幫助!

  本文的源代碼下載下傳:http://www.tracefact.net/sourcecode/Introduction-to-HttpModule.rar

  posted on 2007-11-25 18:50 Jimmy Zhang閱讀(1459) 評論(12) 編輯收藏所屬分類: Asp.Net Architecture

本文轉自

http://www.cnblogs.com/JimmyZhang/archive/2007/11/25/971878.html

繼續閱讀