天天看點

HTTPModule vs HTTPHandler

直接上結論:

HTTPModule:任何請求都将先經過HTTPModule的處理;

HTTPHandler:要為請求構造Response時,将根據特定類型的請求調用相應的HTTPHandler。

一、ASP.NET Application Life Cycle Overview

先來看看ASP.NET應用程式的生命周期是怎樣的。

HTTPModule vs HTTPHandler

當一個請求到來時,IIS将其配置設定給ASP.NET Engine,而後這個請求經由Application pipeline經過一系列處理,最終構造對于特定請求的響應,發送給Client。

重要的是這個pipeline。

二、Pipeline processed by HTTPApplication

目前戲做足了,ASP.NET将建立一個HTTPApplication執行個體,這個執行個體可以 reused by subsequent requests,是以為了性能考慮,可以隻在第一次請求時被執行個體化。若工程中含有Global.asax檔案,則将會建立從HTTPApplication類繼承的子類的執行個體,在子類中你可以對pipeline中的這些event handler進行自定義處理。(你可以為項目中添加一個“全局應用程式類”即Global.asax.cs,可以看到在檔案中列出了許多pipeline中的事件可供重寫)

Pipeline

1. Validate the request

2. Perform URL mapping

3. Raise the BeginRequest event

...

15. Call the ProcessRequest method of the appropriate IHTTPHandler class for the request

24. Raise the EndRequest event

25. Raise the PreSendRequestHeaders event

26. Raise the PreSendRequestContent event

經過pipeline後,response就發給了client,一次請求的生命周期就結束了。特别注意15:在這一步将為特定的request執行個體化一個能夠處理它的HTTPHandler執行個體,并invoke它實作的ProcessRequest接口。如請求的是web page,則将根據擴充名(.aspx)來執行個體化一個對應的IHTTPHandler類,也就是在這個時候,我們通常這樣寫的類:

public partial class MyWebForm : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
    }
}
           

MyWebForm就會被構造,繼而開始Web Page Life Cycle。對!你了解的沒錯兒,ProcessRequest正是代表了Web Page的生命周期。

那HTTPModule和HTTPHandler到底是怎麼用呢?

實際上pinepline是由HTTPModule和HTTPHandler組成的,可以簡單看成是這樣:

HTTPModule vs HTTPHandler

是的,你甚至可以建立一個可以處理請求字尾為自定義擴充名(如.asi)的HTTPHandler。就是說,當你的請求字尾為.asi,ASP.NET将執行個體化你自己的HTTPHanlder來處理,是不是很6?

當然了,還可以通過在HTTPModule上”做手腳”來對所有請求都進行一緻的處理。比如在BeginRequest、EndRequest事件加一句提示,這樣不論對于.aspx或.asi都會生效。

現在來看看具體怎麼實作。

三、My custom HTTPModule and HTTPHandler

找到工程根目錄下名為App_Code的檔案夾,若無則手動建立一個。該檔案夾中的source file将在運作時編譯并緩存。

(1) HTTPModule

實作需要兩步:1. 實作IHTTPModule接口;2. Register your custom HTTPModule

在App_Code檔案夾中新增一個.cs檔案,命名為HelloWorldHTTPModule.cs。自定義的HTTPModule必須實作IHTTPModule接口,在Init中register自己的event handler。

1. 實作接口

我們在BeginRequest和EndRequest事件上增加了我們自己的事件,輸出一段文字。

public class HelloWorldModule : IHttpModule
    {
        public string ModuleName
        {
            get { return "HelloWorldModule"; }
        }

        //Use the Init method to register event handling methods with specific events
        public void Init(HttpApplication application)
        {
            application.BeginRequest += new EventHandler(Application_BeginRequest);
            application.EndRequest += new EventHandler(Application_EndRequest);
        }

        public void Dispose()
        {

        }

        private void Application_BeginRequest(Object o, EventArgs e)
        {
            HttpApplication application = (HttpApplication)o;
            HttpContext context = application.Context;
            string filePath = context.Request.FilePath;
            string fileExtension = VirtualPathUtility.GetExtension(filePath);

            if (fileExtension.Equals(".aspx"))//隻為.aspx請求處理,若要對所有requests處理,請去掉if這個判斷。
            {
                context.Response.Write("<h1><font color=red>" +
                "HelloWorldModule: Beginning of Request" +
                "</font></h1><hr>");
            }
        }

        private void Application_EndRequest(Object o, EventArgs e)
        {
            HttpApplication application = (HttpApplication)o;
            HttpContext context = application.Context;
            string filePath = context.Request.FilePath;
            string fileExtension = VirtualPathUtility.GetExtension(filePath);

            if (fileExtension.Equals(".aspx"))//同上
            {
                context.Response.Write("<h1><font color=red>" +
                "HelloWorldModule: End of Request" +
                "</font></h1><hr>");
            }
        }
    }
           

2. Register my custom HTTPModule

在根目錄下的Web.config檔案中,在<modules> section中注冊HelloWorldModule:

<configuration>
  <system.webServer>
    <modules>
      <add name="AnyNameYouLike" type="HelloWorldModule"/>
    </modules>
  </system.webServer>
</configuration>
           

3. Test

儲存檔案(無需編譯App_Code下的源檔案)。重新打開web page,你會看到在頁面上下都會标記有BeginRequest、EndRequest的資訊。這是因為運作時編譯了你的HTTPModule---HelloWorldModule,是以對于.aspx請求都會有這個資訊。

(2) HTTPHandler

HTTPHandler實作的方式和上述一緻。

1. 實作IHTTPHandler接口

我們想搞一個能夠處理.asi請求的HTTPHandler!

同樣,在App_Code檔案夾中建立一個.cs檔案,命名為HelloAsiHTTPHandler.cs。而後實作IHTTPHandler的兩個接口。

namespace WebApplication6.App_Code
{
    public class HelloAsiHandler : IHttpHandler
    {

        public void ProcessRequest(HttpContext context)
        {
            HttpResponse Response = context.Response;
            Response.Write("<html>");
            Response.Write("<body>");
            Response.Write("<h1>Hello Asi from a synchronous custom HTTPAsiHandler.</h1>");
            Response.Write("</body>");
            Response.Write("</html>");
        }

        public bool IsReusable
        {
            get
            {
                return false;
            }
        }
    }
}
           

2. Register my custom HTTPHandler

在根目錄下的Web.config檔案中,在<handlers> section中注冊HelloWorldModule:

<configuration>
  <system.webServer>
    <handlers>
      <add verb="*" path="*.asi" name="AnythingYouLike" type="WebApplication6.App_Code.HelloAsiHandler"/>
    </handlers>
  </system.webServer>
</configuration>
           

其中,verb表示HTTP類型,如GET、POST;path就是請求的URL,這裡表示任何字尾為.asi的URL;type一定要寫對,注意由于屬于命名空間裡的,是以要加上限定。

3. Test

儲存運作,如目前網頁URL為http://localhost:29233/WebForm1.aspx, 試試修改浏覽器URL字尾為.asi。不要改了域名和端口!如http://localhost:29233/hisSixUncle.asi,歡快地擊打Enter鍵,不出意外的話page将顯示一個<h1>标題”Hello Asi from a synchronous custom HTTPAsiHandler.“。

四、總結

最近項目不忙,看了好多MSDN終于比以前小白隻知道寫卻不知道為什麼的時候強多了。寫出一些心得體會分享一下,肯定有不妥之處,還望指正,希望沒有誤導你。。

記以供日後溫習。

引用一句《程式員:從小工到專家》的話,”有的程式員根本不知道自己寫的代碼都做了些什麼“。感覺這就是在說我[捂臉]。

五、References (能把這些多看幾遍對提高ASP.NET的大局觀很有幫助, especially 1 & 2)

1. ASP.NET Application Life Cycle Overview for IIS 7.0

2. Understanding ASP.NET View State

3. HTTP Handlers and HTTP Modules Overview

4. Walkthrough: Creating and Registering a Custom HTTP Module

5. Walkthrough: Creating a Synchronous HTTP Handler