天天看點

深入了解asp.net裡的HttpModule機制轉自http://jeffwongishandsome.cnblogs.com/

轉自http://jeffwongishandsome.cnblogs.com/

1、asp.net的HTTP請求處理過程

深入了解asp.net裡的HttpModule機制轉自http://jeffwongishandsome.cnblogs.com/

說明:

(1)、用戶端浏覽器向伺服器發出一個http請求,此請求會被inetinfo.exe程序截獲,然後轉交給aspnet_isapi.dll程序,接着它又通過Http Pipeline的管道,傳送給aspnet_wp.exe這個程序,接下來就到了.net framework的HttpRunTime進行中心,處理完畢後就發送給使用者浏覽器。

(2)、當一個http請求被送入到HttpRuntime之後,這個Http請求會繼續被送入到一個被稱之為HttpApplication Factory的一個容器當中,而這個容器會給出一個HttpApplication執行個體來處理傳遞進來的http請求,而後這個Http請求會依次進入到如下幾個容器中:HttpModule --> HttpHandler Factory --> HttpHandler。當系統内部的HttpHandler的ProcessRequest方法處理完畢之後,整個Http Request就被處理完成了,用戶端也就得到相應的東東了。

(3)完整的http請求在asp.net framework中的處理流程:

HttpRequest-->inetinfo.exe->ASPNET_ISAPI.DLL-->Http Pipeline-->ASPNET_WP.EXE-->HttpRuntime-->HttpApplication Factory-->HttpApplication-->HttpModule-->HttpHandler Factory-->HttpHandler-->HttpHandler.ProcessRequest()

ps:紅色的HttpApplication執行個體在HttpModule的Init方法中會用到。

(4)如果想在中途截獲一個httpRequest并做些自己的處理,就應該在HttpRuntime運作時内部來做到這一點,确切的說是在HttpModule這個容器中來實作。

2、HttpModule工作原理

負責監聽HttpRequest,同時對HttpRequest增添或者過濾掉一部分内容。也就是說,當一個HTTP請求到達HttpModule時,整個ASP.NET Framework系統還并沒有對這個HTTP請求做任何處理,也就是說此時對于HTTP請求來講,HttpModule是一個HTTP請求的“必經之路”,是以可以在這個HTTP請求傳遞到真正的請求進行中心(HttpHandler)之前附加一些需要的資訊在這個HTTP請求資訊之上,或者針對截獲的這個HTTP請求資訊作一些額外的工作,或者在某些情況下幹脆終止滿足一些條件的HTTP請求,進而可以起到一個Filter過濾器的作用。

HttpModule實作了接口IHttpModule,我們可以自定義實作該接口的類,進而取代HttpModule。

asp.net預設的HttpModule如下:

        System.Web.SessionState.SessionStateModule;

        System.Web.Security.WindowsAuthenticationModule;

        System.Web.Security.FormsAuthenticationModule;

        System.Web.Security.PassportAuthenticationModule;

        System.Web.Security.UrlAuthorizationModule;

        System.Web.Security.FileAuthorizationModule;

3、編寫自己的HttpModule

要實作HttpModule,必須實作接口IHttpModule。下面是IHttpModule接口分析:

深入了解asp.net裡的HttpModule機制轉自http://jeffwongishandsome.cnblogs.com/

using System;

namespace System.Web

{

    // Summary:

    //     Provides module initialization and disposal events to the implementing class.

    public interface IHttpModule

    {

        // Summary:

        //     Disposes of the resources (other than memory) used by the module that implements

        //     System.Web.IHttpModule.

        //   銷毀不再被HttpModule使用的資源

        void Dispose();

        //

        //     Initializes a module and prepares it to handle requests.

        // Parameters:

        //   context:

        //     An System.Web.HttpApplication that provides access to the methods, properties,

        //     and events common to all application objects within an ASP.NET application

        // 初始化一個Module,為捕獲HttpRequest做準備

        void Init(HttpApplication context);

    }

}

下面是自己的HttpModule:

深入了解asp.net裡的HttpModule機制轉自http://jeffwongishandsome.cnblogs.com/

using System.Collections.Generic;

using System.Text;

using System.Web; //要在自己的類庫中添加System.Web引用

namespace MyHttpModule

    class MySelfHttpModule : IHttpModule

        public void Dispose() { }

        public void Init(HttpApplication application)

        {

            application.BeginRequest += new EventHandler(Application_BeginRequest);

            application.EndRequest += new EventHandler(Application_EndRequest);

        }

        // 自己要針對一些事情進行處理的兩個方法

        private void Application_BeginRequest(object sender, EventArgs e)

            HttpApplication application = sender as HttpApplication;

            HttpContext context = application.Context;

            HttpRequest request = application.Request;

            HttpResponse response = application.Response;

            response.Write("我來自自定義HttpModule中的BeginRequest<br />");

        private void Application_EndRequest(object sender, EventArgs e)

            response.Write("我來自自定義HttpModule中的EndRequest<br />");

最後在web項目中使用自己的HttpModule:

(1)添加引用

深入了解asp.net裡的HttpModule機制轉自http://jeffwongishandsome.cnblogs.com/

a、不需要在整個web項目添加對類庫的引用,隻是複制一份到bin目錄下即可。

b、default.aspx的cs檔案:

深入了解asp.net裡的HttpModule機制轉自http://jeffwongishandsome.cnblogs.com/

using System.Data;

using System.Configuration;

using System.Web;

using System.Web.Security;

using System.Web.UI;

using System.Web.UI.WebControls;

using System.Web.UI.WebControls.WebParts;

using System.Web.UI.HtmlControls;

public partial class _Default : System.Web.UI.Page

    protected void Page_Load(object sender, EventArgs e)

        Response.Write("<br/>來自Default.aspx頁面<br/>");

(2)web.config的節點配置

    IIS 7.0 經典模式以及較早的 IIS 版本

 在Web.config的system.web标簽中添加:

<system.web>
    <compilation debug="true" targetFramework="4.5"/>
    <httpRuntime targetFramework="4.5"/>
    <httpModules>
      <add name="MyHttpModuleTest" type="MyHttpModule.MyHttpModule,MyHttpModule" />
    </httpModules>
  </system.web>      

  IIS 7.0 內建模式以上。

    在Web.config的system.webServer标簽中添加:   

<system.webServer>
    <modules>
      <add name="MyHttpModuleTest" type="MyHttpModule.MyHttpModule,MyHttpModule" />
    </modules>
  </system.webServer>      

a、name可以随意指定,沒有影響。

b、type有兩個參數,第一個表示具體哪個類,第二個表示是哪個dll。

最後運作web項目,你會看到每個頁面都會Response.Write兩句話出來。

4、HttpModule内部事件機制和生命周期

HttpModule對HttpApplication執行個體進行處理,而HttpApplication有很多事件(對應不同的生命期),這樣就衍生出HttpModule内部事件機制和生命周期。

(1)HttpModule的事件

深入了解asp.net裡的HttpModule機制轉自http://jeffwongishandsome.cnblogs.com/

a、BenginRequest和EndRequest分别是HttpModule容器最開始的和最後的事件;

b、EndRequest之後還會觸發PreSendRequestHeaders事件和PreSendRequestContent事件,這不是在HttpModule外的兩個事件,表示HttpModule結束,即将開始向Client發送資料。

(2)、驗證HttpModule生命周期

與HttpHandler的互動:

深入了解asp.net裡的HttpModule機制轉自http://jeffwongishandsome.cnblogs.com/

 a、HttpModule容器會将HttpRequest傳遞到HttpHandler容器,這個時間點是ResolveRequestCache事件

 b、HttpModule容器會建立HttpHandler執行個體作為入口——Session從此生效

 c、觸發AcquireRequestState事件以及PreRequestHandlerExecute事件

 d、HttpModule容器便将對HttpRequest的控制權轉讓給HttpHandler容器

 e、HttpHandler容器處理HttpRequest——使用自身的ProcessRequest方法,将對其控制權又還給HttpModule容器——之後Session失效。

驗證生命周期代碼:

深入了解asp.net裡的HttpModule機制轉自http://jeffwongishandsome.cnblogs.com/

    public class ValidaterHttpModuleEvents : IHttpModule

        public void Dispose()

        { }

        /// <summary>

        /// 驗證HttpModule事件機制

        /// </summary>

        /// <param name="application"></param>

            application.BeginRequest += new EventHandler(application_BeginRequest);

            application.EndRequest += new EventHandler(application_EndRequest);

            application.AcquireRequestState += new EventHandler(application_AcquireRequestState);

            application.AuthenticateRequest += new EventHandler(application_AuthenticateRequest);

            application.AuthorizeRequest += new EventHandler(application_AuthorizeRequest);

            application.PreRequestHandlerExecute += new EventHandler(application_PreRequestHandlerExecute);

            application.PostRequestHandlerExecute += new EventHandler(application_PostRequestHandlerExecute);

            application.ReleaseRequestState += new EventHandler(application_ReleaseRequestState);

            application.ResolveRequestCache += new EventHandler(application_ResolveRequestCache);

            application.PreSendRequestHeaders += new EventHandler(application_PreSendRequestHeaders);

            application.PreSendRequestContent += new EventHandler(application_PreSendRequestContent);

        private void application_BeginRequest(object sender, EventArgs e)

            HttpApplication application = (HttpApplication)sender;

            application.Context.Response.Write("application_BeginRequest<br/>");

        private void application_EndRequest(object sender, EventArgs e)

            application.Context.Response.Write("application_EndRequest<br/>");

        private void application_PreRequestHandlerExecute(object sender, EventArgs e)

            application.Context.Response.Write("application_PreRequestHandlerExecute<br/>");

        private void application_PostRequestHandlerExecute(object sender, EventArgs e)

            application.Context.Response.Write("application_PostRequestHandlerExecute<br/>");

        private void application_ReleaseRequestState(object sender, EventArgs e)

            application.Context.Response.Write("application_ReleaseRequestState<br/>");

        private void application_AcquireRequestState(object sender, EventArgs e)

            application.Context.Response.Write("application_AcquireRequestState<br/>");

        private void application_PreSendRequestContent(object sender, EventArgs e)

            application.Context.Response.Write("application_PreSendRequestContent<br/>");

        private void application_PreSendRequestHeaders(object sender, EventArgs e)

            application.Context.Response.Write("application_PreSendRequestHeaders<br/>");

        private void application_ResolveRequestCache(object sender, EventArgs e)

            application.Context.Response.Write("application_ResolveRequestCache<br/>");

        private void application_AuthorizeRequest(object sender, EventArgs e)

            application.Context.Response.Write("application_AuthorizeRequest<br/>");

        private void application_AuthenticateRequest(object sender, EventArgs e)

            application.Context.Response.Write("application_AuthenticateRequest<br/>");

注:修改配置檔案中的httpModules節點中的type對應的類名即可.

5、其他

(1)、加載兩個或多個自定義的HttpModule

這裡以兩個自定義HttpModule舉例.

修改配置檔案中的httpModules節點:

<add name="HttpModule1" type="MyHttpModule.HttpModule1,MyHttpModule"/>

<add name="HttpModule2" type="MyHttpModule.HttpModule2,MyHttpModule"/>

HttpModule1和HttpModule2模仿ValidaterHttpModuleEvents編寫(除了類名改變外,事件和方法不變),不貼代碼了。運作結果如下:

深入了解asp.net裡的HttpModule機制轉自http://jeffwongishandsome.cnblogs.com/

分析:

a、從運作結果可以看到,在web.config檔案中引入自定義HttpModule的順序就決定了多個自定義HttpModule在處理一個HTTP請求的接管順序;

b、系統預設那幾個HttpModule是最先被ASP.NET Framework所加載上去的,對外部是透明的。

(2)、利用HttpModule實作終止此次HttpRequest請求

在BeginRequest事件中,使用HttpApplication.CompleteRequest()方法可以實作當滿足一定條件時終止此次HttpRequest請求。看代碼:

    public class CompleteRequestHttpModule : IHttpModule

            application.Context.Response.Write("請求

深入了解asp.net裡的HttpModule機制轉自http://jeffwongishandsome.cnblogs.com/

<br/>");

            application.CompleteRequest(); //在BeginRequest事件中,使用HttpApplication.CompleteRequest()方法實作

            application.Context.Response.Write("請求被終止

深入了解asp.net裡的HttpModule機制轉自http://jeffwongishandsome.cnblogs.com/

");

a、對于一個HttpModule,在BeginRquest中終止,但是仍然會調用EndRequest事件,以及PreSendRequestHeaders事件和PreSendRequestContent事件。也可以說是直接跳轉到EndRequest事件,而不會調用這期間的事件

b、如果有兩個HttpModule,在第一個HttpModule的BeginRequest中終止,僅僅不會調用第二個HttpModule的BeginRequest,但仍然會調用兩個EndRequest事件,以及PreSendRequestHeaders事件和PreSendRequestContent事件。看下面的圖示:

深入了解asp.net裡的HttpModule機制轉自http://jeffwongishandsome.cnblogs.com/

繼續閱讀