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

来源:https://www.cnblogs.com/taotaozhuanyong/archive/2019/09/24/11581464.html
-Advertisement-
Play Games

https://www.cnblogs.com/JimmyZhang/archive/2007/09/04/880967.html IHttpModule HTTPRuntime(運行時)。在一個控制台程式中,程式的入口是Program中的Main方法。那麼,一個網站的入口在哪裡呢?在最開始的ash ...


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裡面的事件註冊動作。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 第一步 接下來我們將看見如何在 Python 中運行一個傳統的“Hello World”程式。Python教程本章將會教你如何編寫、保存與運行 Python 程式。 通過 Python 來運行的你的程式有兩種方法——使用互動式解釋器提示符或直接運行一個源代碼文件。我們將瞭解如何使用他們二者的功能。 ...
  • 在應用中需要使用調度框架來做一些統計的功能,可惜在Windows上可用的不多,最後選擇了APScheduler這個調度器。 用法不多介紹,只總結一下在使用中遇到的坑。 app_context 問題 凡是在APScheduler中調用的function,只要用到初始化跟app相關的對象(如db,mai ...
  • 一、迴圈 輸入一個數字,輸出該數字有幾位 二、while迴圈 迴圈體內要有改變條件的機會,避免死迴圈 while迴圈的意思就是:當條件滿足時,不斷地重覆迴圈體內的語句 迴圈執行之前判斷是否繼續迴圈,所以有可能迴圈一次也沒有被執行 看我們上面的代碼,是否有點多餘的成分,我們來進行改造,但是還有一個問題 ...
  • # 深淺拷貝 1 import copy 2 3 a = ["xiaoming",111,[5000,2000]] 4 b = a 5 print("b:%s" % b) #a,b共用同一塊記憶體地址,輸出結果b:['xiaoming', 111, [5000, 2000]] 6 7 #淺拷貝只拷貝第 ...
  • 通過以下思維導圖,學習委托的基本概念,後面著重講解委托的運用,希望通過最簡單的方式收穫更多的知識。 1.委托的各種寫法 1、委托 委托名=new 委托(會調用的方法名); 委托名(參數); 2、委托 委托名 =會調用的方法名; 委托名(參數); 3、匿名方法:委托 委托名=delegate(參數){ ...
  • ASP.NET有個大佬,HttpContext(在.Net Core中依然是它)Http請求的上下文,任何一個環節都是需要HttpContext的,需要的參數信息,處理的中間結果,最終的結果,都是放在HttpContext,是一個貫穿全局的對象。 所謂的六大對象,其實就是HttpContext的屬性 ...
  • public class CEBSignClient { public void StartSignClient() { } private static SignClientConfig _signClientConfig; public static SignClientConfig CebSi ...
  • 瀏覽器到網站程式 上一篇中,介紹IHttpModule的時候,自定義一個類CustomHttpModule繼承自IHttpModule,自定義一個事件,並配合配置文件,就可以執行自定義Module中的Init方法。我們在瀏覽一個View視圖,並新建一個WebForm頁面,也瀏覽一下 我們可以看出來, ...
一周排行
    -Advertisement-
    Play Games
  • Dapr Outbox 是1.12中的功能。 本文只介紹Dapr Outbox 執行流程,Dapr Outbox基本用法請閱讀官方文檔 。本文中appID=order-processor,topic=orders 本文前提知識:熟悉Dapr狀態管理、Dapr發佈訂閱和Outbox 模式。 Outbo ...
  • 引言 在前幾章我們深度講解了單元測試和集成測試的基礎知識,這一章我們來講解一下代碼覆蓋率,代碼覆蓋率是單元測試運行的度量值,覆蓋率通常以百分比表示,用於衡量代碼被測試覆蓋的程度,幫助開發人員評估測試用例的質量和代碼的健壯性。常見的覆蓋率包括語句覆蓋率(Line Coverage)、分支覆蓋率(Bra ...
  • 前言 本文介紹瞭如何使用S7.NET庫實現對西門子PLC DB塊數據的讀寫,記錄了使用電腦模擬,模擬PLC,自至完成測試的詳細流程,並重點介紹了在這個過程中的易錯點,供參考。 用到的軟體: 1.Windows環境下鏈路層網路訪問的行業標準工具(WinPcap_4_1_3.exe)下載鏈接:http ...
  • 從依賴倒置原則(Dependency Inversion Principle, DIP)到控制反轉(Inversion of Control, IoC)再到依賴註入(Dependency Injection, DI)的演進過程,我們可以理解為一種逐步抽象和解耦的設計思想。這種思想在C#等面向對象的編 ...
  • 關於Python中的私有屬性和私有方法 Python對於類的成員沒有嚴格的訪問控制限制,這與其他面相對對象語言有區別。關於私有屬性和私有方法,有如下要點: 1、通常我們約定,兩個下劃線開頭的屬性是私有的(private)。其他為公共的(public); 2、類內部可以訪問私有屬性(方法); 3、類外 ...
  • C++ 訪問說明符 訪問說明符是 C++ 中控制類成員(屬性和方法)可訪問性的關鍵字。它們用於封裝類數據並保護其免受意外修改或濫用。 三種訪問說明符: public:允許從類外部的任何地方訪問成員。 private:僅允許在類內部訪問成員。 protected:允許在類內部及其派生類中訪問成員。 示 ...
  • 寫這個隨筆說一下C++的static_cast和dynamic_cast用在子類與父類的指針轉換時的一些事宜。首先,【static_cast,dynamic_cast】【父類指針,子類指針】,兩兩一組,共有4種組合:用 static_cast 父類轉子類、用 static_cast 子類轉父類、使用 ...
  • /******************************************************************************************************** * * * 設計雙向鏈表的介面 * * * * Copyright (c) 2023-2 ...
  • 相信接觸過spring做開發的小伙伴們一定使用過@ComponentScan註解 @ComponentScan("com.wangm.lifecycle") public class AppConfig { } @ComponentScan指定basePackage,將包下的類按照一定規則註冊成Be ...
  • 操作系統 :CentOS 7.6_x64 opensips版本: 2.4.9 python版本:2.7.5 python作為腳本語言,使用起來很方便,查了下opensips的文檔,支持使用python腳本寫邏輯代碼。今天整理下CentOS7環境下opensips2.4.9的python模塊筆記及使用 ...