.NET MVC5簡介(五)管道處理模型IHttpModule


https://www.cnblogs.com/JimmyZhang/archive/2007/09/04/880967.html

IHttpModule

HTTPRuntime(運行時)。在一個控制台程序中,程序的入口是Program中的Main方法。那么,一個網站的入口在哪里呢?在最開始的ashx中,有個ProcessRequest方法,后來在WebForm中,在后台是一個不分類,繼承自Page類,在Page_Load方法中去寫代碼。其實Page類型也有一個ProcessRequest的虛方法。

 

 

 都是這個ProcessRequest方法來處理請求的。在MVC中也是如此。在MVC中,任何一個Http請求,一定有一個IHttpHandler來處理,在這個接口中,定義了一個ProcessRequest方法。HttpApplication繼承自IHttpHandler接口。任何一個Http請求就是一個HttpApplication對象來處理的,然后處理過程固定包含權限認證、緩存處理、Session處理、Cookie出庫、生成html、輸出客戶端,與此同時,千千萬萬的開發者,又有各種各樣的擴展訴求,任何一個環節都有可能擴展,如果是我們來設計,該怎么設計?

其實在MVC框架里面,用到的是觀察者模式:

在HttpApplication類型,有這些事件:

 //
        // 摘要:
        //     Occurs just before ASP.NET sends HTTP headers to the client.
        public event EventHandler PreSendRequestHeaders;
 //
        // 摘要:
        //     Occurs when the handler is selected to respond to the request.
        public event EventHandler MapRequestHandler;
 //
        // 摘要:
        //     Occurs when the application is disposed.
        public event EventHandler Disposed;
 //
        // 摘要:
        //     Occurs as the first event in the HTTP pipeline chain of execution when ASP.NET
        //     responds to a request.
        public event EventHandler BeginRequest;
 //
        // 摘要:
        //     Occurs when a security module has established the identity of the user.
        public event EventHandler AuthenticateRequest;
 //
        // 摘要:
        //     Occurs when a security module has established the identity of the user.
        public event EventHandler PostAuthenticateRequest;
 //
        // 摘要:
        //     Occurs when a security module has verified user authorization.
        public event EventHandler AuthorizeRequest;
 //
        // 摘要:
        //     Occurs when the user for the current request has been authorized.
        public event EventHandler PostAuthorizeRequest;
 //
        // 摘要:
        //     Occurs when ASP.NET finishes an authorization event to let the caching modules
        //     serve requests from the cache, bypassing execution of the event handler (for
        //     example, a page or an XML Web service).
        public event EventHandler ResolveRequestCache;
 //
        // 摘要:
        //     Occurs when ASP.NET bypasses execution of the current event handler and allows
        //     a caching module to serve a request from the cache.
        public event EventHandler PostResolveRequestCache;
 //
        // 摘要:
        //     Occurs just before ASP.NET sends content to the client.
        public event EventHandler PreSendRequestContent;
 //
        // 摘要:
        //     Occurs when ASP.NET has mapped the current request to the appropriate event handler.
        public event EventHandler PostMapRequestHandler;
 //
        // 摘要:
        //     Occurs when ASP.NET has completed processing all the event handlers for the System.Web.HttpApplication.LogRequest
        //     event.
        public event EventHandler PostLogRequest;
 //
        // 摘要:
        //     Occurs when the managed objects that are associated with the request have been
        //     released.
        public event EventHandler RequestCompleted;
 //
        // 摘要:
        //     Occurs when the request state (for example, session state) that is associated
        //     with the current request has been obtained.
        public event EventHandler PostAcquireRequestState;
 //
        // 摘要:
        //     Occurs just before ASP.NET starts executing an event handler (for example, a
        //     page or an XML Web service).
        public event EventHandler PreRequestHandlerExecute;
 //
        // 摘要:
        //     Occurs when the ASP.NET event handler (for example, a page or an XML Web service)
        //     finishes execution.
        public event EventHandler PostRequestHandlerExecute;
 //
        // 摘要:
        //     Occurs after ASP.NET finishes executing all request event handlers. This event
        //     causes state modules to save the current state data.
        public event EventHandler ReleaseRequestState;
 //
        // 摘要:
        //     Occurs when ASP.NET has completed executing all request event handlers and the
        //     request state data has been stored.
        public event EventHandler PostReleaseRequestState;
 //
        // 摘要:
        //     Occurs when ASP.NET finishes executing an event handler in order to let caching
        //     modules store responses that will be used to serve subsequent requests from the
        //     cache.
        public event EventHandler UpdateRequestCache;
 //
        // 摘要:
        //     Occurs when ASP.NET finishes updating caching modules and storing responses that
        //     are used to serve subsequent requests from the cache.
        public event EventHandler PostUpdateRequestCache;
 //
        // 摘要:
        //     Occurs just before ASP.NET performs any logging for the current request.
        public event EventHandler LogRequest;
 //
        // 摘要:
        //     Occurs when ASP.NET acquires the current state (for example, session state) that
        //     is associated with the current request.
        public event EventHandler AcquireRequestState;
 //
        // 摘要:
        //     Occurs as the last event in the HTTP pipeline chain of execution when ASP.NET
        //     responds to a request.
        public event EventHandler EndRequest;
 //
        // 摘要:
        //     Occurs when an unhandled exception is thrown.
        public event EventHandler Error;
View Code

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 這里用的是觀察者模式,把固定的步驟直接寫在handler里面,在步驟前后分別放一個事件,然后開發者可以對事件注冊動作,等着請求進來了,然后就可以按照順訊執行一下。這種設計是不是很完美?但是仍有不完美的地方,就是每個請求都要執行這些事件,太多管閑事了。在.NET Core中出現了中間件,比這種更加完美。后續再詳細介紹。

請見下列代碼

 public class HttpProcessDemo
 {
     public class HttpApplicationDemo : IHttpHandler
     {
         public bool IsReusable => true;

         public event Action BeginRequest;
         public event Action EndRequest;
         public event Action PreSomething1Handler;
         public event Action PostSomething1Handler;
         public event Action PreSomething2Handler;
         public event Action PostSomething2Handler;
         public event Action PreSomething3Handler;
         public event Action PostSomething3Handler;
         public event Action PreSomething4Handler;
         public event Action PostSomething4Handler;
         public event Action PreSomething5Handler;
         public event Action PostSomething5Handler;
         public event Action PreSomething6Handler;
         public event Action PostSomething6Handler;
         public void ProcessRequest(HttpContext context)
         {
             this.BeginRequest?.Invoke();

             this.PreSomething1Handler?.Invoke();
             Console.WriteLine("Something 1");
             this.PostSomething1Handler?.Invoke();

             this.PreSomething2Handler?.Invoke();
             Console.WriteLine("Something 2");
             this.PostSomething2Handler?.Invoke();
             this.PreSomething3Handler?.Invoke();
             Console.WriteLine("Something 3");
             this.PostSomething3Handler?.Invoke();
             this.PreSomething4Handler?.Invoke();
             Console.WriteLine("Something 4");
             this.PostSomething4Handler?.Invoke();

             this.PreSomething5Handler?.Invoke();
             Console.WriteLine("Something 5");
             this.PostSomething5Handler?.Invoke();
             this.PreSomething6Handler?.Invoke();
             Console.WriteLine("Something 6");
             this.PostSomething6Handler?.Invoke();

             this.EndRequest?.Invoke();
         }
         //任何請求進來,只能是 123456
         //事件升級后,可以在程序啟動時,實例化HttpApplicationDemo后,可以給事件注冊動作,請求再進來時,處理不僅是123456了,還有多個事件里面的動作
     }
View Code

對HttpApplication里面的事件進行動作注冊,就叫IHttpModule。

自定義一個HttpModule+配置文件注冊,然后任何一個請求都會執行Init里面注冊給Application事件的動作。

 

 

 

 public class CustomHttpModule : IHttpModule
 {
     public void Dispose()
     {
         Console.WriteLine();
     }

     public event EventHandler CustomHttpModuleHandler;

     /// <summary>
     /// 注冊動作
     /// </summary>
     /// <param name="context"></param>
     public void Init(HttpApplication application)
     {
         application.BeginRequest += (s, e) =>
           {
               this.CustomHttpModuleHandler?.Invoke(application, null);
           };
         //application.EndRequest += (s, e) =>
         //{
         //    HttpContext.Current.Response.Write("CustomHttpModule.EndRequest");
         //};
         #region 為每一個事件,都注冊了一個動作,向客戶端輸出信息
         application.AcquireRequestState += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>來自MyCustomModule 的處理,{0}請求到達 {1}</h1><hr>", DateTime.Now.ToString(), "AcquireRequestState        "));
         application.AuthenticateRequest += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>來自MyCustomModule 的處理,{0}請求到達 {1}</h1><hr>", DateTime.Now.ToString(), "AuthenticateRequest        "));
         application.AuthorizeRequest += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>來自MyCustomModule 的處理,{0}請求到達 {1}</h1><hr>", DateTime.Now.ToString(), "AuthorizeRequest           "));
         application.BeginRequest += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>來自MyCustomModule 的處理,{0}請求到達 {1}</h1><hr>", DateTime.Now.ToString(), "BeginRequest               "));
         application.Disposed += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>來自MyCustomModule 的處理,{0}請求到達 {1}</h1><hr>", DateTime.Now.ToString(), "Disposed                   "));
         application.EndRequest += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>來自MyCustomModule 的處理,{0}請求到達 {1}</h1><hr>", DateTime.Now.ToString(), "EndRequest                 "));
         application.Error += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>來自MyCustomModule 的處理,{0}請求到達 {1}</h1><hr>", DateTime.Now.ToString(), "Error                      "));
         application.LogRequest += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>來自MyCustomModule 的處理,{0}請求到達 {1}</h1><hr>", DateTime.Now.ToString(), "LogRequest                 "));
         application.MapRequestHandler += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>來自MyCustomModule 的處理,{0}請求到達 {1}</h1><hr>", DateTime.Now.ToString(), "MapRequestHandler          "));
         application.PostAcquireRequestState += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>來自MyCustomModule 的處理,{0}請求到達 {1}</h1><hr>", DateTime.Now.ToString(), "PostAcquireRequestState    "));
         application.PostAuthenticateRequest += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>來自MyCustomModule 的處理,{0}請求到達 {1}</h1><hr>", DateTime.Now.ToString(), "PostAuthenticateRequest    "));
         application.PostAuthorizeRequest += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>來自MyCustomModule 的處理,{0}請求到達 {1}</h1><hr>", DateTime.Now.ToString(), "PostAuthorizeRequest       "));
         application.PostLogRequest += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>來自MyCustomModule 的處理,{0}請求到達 {1}</h1><hr>", DateTime.Now.ToString(), "PostLogRequest             "));
         application.PostMapRequestHandler += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>來自MyCustomModule 的處理,{0}請求到達 {1}</h1><hr>", DateTime.Now.ToString(), "PostMapRequestHandler      "));
         application.PostReleaseRequestState += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>來自MyCustomModule 的處理,{0}請求到達 {1}</h1><hr>", DateTime.Now.ToString(), "PostReleaseRequestState    "));
         application.PostRequestHandlerExecute += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>來自MyCustomModule 的處理,{0}請求到達 {1}</h1><hr>", DateTime.Now.ToString(), "PostRequestHandlerExecute  "));
         application.PostResolveRequestCache += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>來自MyCustomModule 的處理,{0}請求到達 {1}</h1><hr>", DateTime.Now.ToString(), "PostResolveRequestCache    "));
         application.PostUpdateRequestCache += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>來自MyCustomModule 的處理,{0}請求到達 {1}</h1><hr>", DateTime.Now.ToString(), "PostUpdateRequestCache     "));
         application.PreRequestHandlerExecute += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>來自MyCustomModule 的處理,{0}請求到達 {1}</h1><hr>", DateTime.Now.ToString(), "PreRequestHandlerExecute   "));
         application.PreSendRequestContent += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>來自MyCustomModule 的處理,{0}請求到達 {1}</h1><hr>", DateTime.Now.ToString(), "PreSendRequestContent      "));
         application.PreSendRequestHeaders += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>來自MyCustomModule 的處理,{0}請求到達 {1}</h1><hr>", DateTime.Now.ToString(), "PreSendRequestHeaders      "));
         application.ReleaseRequestState += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>來自MyCustomModule 的處理,{0}請求到達 {1}</h1><hr>", DateTime.Now.ToString(), "ReleaseRequestState        "));
         application.RequestCompleted += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>來自MyCustomModule 的處理,{0}請求到達 {1}</h1><hr>", DateTime.Now.ToString(), "RequestCompleted           "));
         application.ResolveRequestCache += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>來自MyCustomModule 的處理,{0}請求到達 {1}</h1><hr>", DateTime.Now.ToString(), "ResolveRequestCache        "));
         application.UpdateRequestCache += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>來自MyCustomModule 的處理,{0}請求到達 {1}</h1><hr>", DateTime.Now.ToString(), "UpdateRequestCache         "));
         #endregion
     }
 }
View Code

訪問下頁面,就是這樣的結果:

 

 

 正常流程下,會按照順序執行19個事件。

學完HttpModule,我們可以做點什么有用的擴展?

  任何一個請求都會執行HttpModuleInit里面注冊給Application的事件

  1、日志-性能監控

  2、權限

  3、緩存

  4、頁面加點東西

  5、請求過濾

  6、MVC就是一個Module的擴展

不適合的:不是針對全部請求的,就不太適合用Module,因為有性能損耗

  1、多語言,根據Cookie信息去查詢不同的數據做不同的展示,如果是全部一套處理,最后HttpModule攔截+處理,適合httpModule

  2、跳轉到不同界面,也不合適

  3、防盜鏈,針對一類的后綴來處理的,而不是全部請求---判斷----再防盜鏈

在HttpModule里面發布一個CustomHttpModuleHandler,在Global增加一個動作CustomHttpModuleBingle_CustomHttpModuleHandler(配置文件module名稱_module里面事件名稱),請求響應時,該事件會執行

protected void CustomHttpModuleBingle_CustomHttpModuleHandler(object sender, EventArgs e)
{
    this.logger.Info("this is CustomHttpModuleBingle_CustomHttpModuleHandler");
}

HttpModule是對HttpApplication的事件動作注冊動作,Global是對HttpModule里面的事件注冊動作。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM