1. 程式人生 > >HttpApplication的認識與加深理解

HttpApplication的認識與加深理解

HttpApplication物件是經由HttpApplicationFactory.GetApplicationInstance(並最終呼叫HttpRuntime.CreateNonPublicInstance)建立的HttpApplicationFactory它的主要任務是使用 URL 資訊來查詢 URL 虛擬目錄和彙集的 HttpApplication 物件之間的匹配關係。



這個工廠類的行為概括為有以下幾點
1、工廠類維護, HttpApplication 物件池並使用它們來處理應用程式的請求。池的壽命與應用程式的壽命相同。 
2、應用程式的第一個請求到達時,工廠類提取有關應用程式型別的資訊(global.asax 類)、設定用於監視更改的檔案、建立應用程式狀態並觸發 Application_OnStart 事件。工廠類從池中獲取一個 HttpApplication 例項,並將要處理的請求放入例項中。如果沒有可用的物件,則建立一個新的 HttpApplication 物件。要建立 HttpApplication 物件,需要先完成 global.asax 應用程式檔案的編譯。
3、HttpApplication 開始處理請求,並且只能在完成這個請求後才能處理新的請求。如果收到來自同一資源的新請求,則由池中的其他物件來處理。 
4、應用程式物件允許所有註冊的 HTTP 模組對請求進行預處理,並找出最適合處理請求的處理程式型別。這通過查詢請求的 URL 的擴充套件和配置檔案中的資訊來完成。

HttpApplicationFactory.GetApplicationInstance建立HttpApplication例項中有三個關鍵方法:

HttpApplicationFactory._theApplicationFactory.EnsureInited()  該方法檢查HttpApplicationFactory是否被初始化,如果沒有,就通過HttpApplicationFactory.Init()進行初始化。在Init()中,先獲取global.asax檔案的完整路徑,然後呼叫CompileApplication()對global.asax進行編譯。

HttpApplicationFactory._theApplicationFactory.EnsureAppStartCalled(context)  建立特定的HttpApplication例項,觸發ApplicationOnStart事件,執行ASP.global_asax中的Application_Start(object sender, EventArgs e)方法。這裡建立的HttpApplication例項在處理完事件後,就被回收。

HttpApplicationFactory._theApplicationFactory.GetNormalApplicationInstance(context) 該方法建立HttpApplication例項並進行初始化,呼叫System.Web.HttpApplication.InitInternal()方法。建立HttpApplication例項是根據實際的_theApplicationType進行建立。如果Web目錄中沒有global.asa檔案,也就是說沒有動態編譯生成ASP.global_asax型別,那就直接例項化  HttpApplication。如果建立了ASP.global_asax型別,那就對ASP.global_asa進行例項化。

建立HttpApplication例項之後就是呼叫例項的InitInternal方法。
InitInternal方法的主要功能如下:
  1. InitModules():根據Web.Config的設定,建立相應的HttpModules。

  2. HookupEventHandlersForAppplicationAndModules:根據發生的事件,呼叫HttpApplication例項中相應的事件處理函式。

  3. 建立很多實現IExecutionStep介面的類的例項並新增到當前HttpApplication例項的_execSteps中,等待回撥時執行。從這裡我們可以看到HttpApplication是以非同步的方式處理請求, 對請求的很多處理工作都放入了_execStep等待回撥時執行。

     _execStep中主要的處理工作如下:
    1) 對請求的路徑進行安全檢查,禁止非法路徑訪問(ValidatePathExecutionStep)。
    2) 如果設定了UrlMappings, 進行RewritePath(UrlMappingsExecutionStep)。
    3) 執行事件處理函式,比如:BeginRequest、AuthenticateRequest等等。

下面就是獲取處理當前請求的HttpHandler,ASP.NET頁面的動態編譯也是在這裡進行的。至此HttpApplication流程將會轉到HttpHandler流程.也就是說HttpApplication 物件負責查詢應該使用哪種處理程式來處理請求。HttpApplication 物件還負責檢測對動態建立的、表示資源的程式集(如 .aspx 頁面或 .asmx Web 服務)所進行的更改。如果檢測到更改,應用程式物件將確保編譯並載入所請求的資源的最新來源。HttpApplication呼叫ProcessRequest方法來處理使用者請求,此方法會呼叫對應的HttpHandler來處理使用者請求,HttpHandler根據使用者請求的檔案的副檔名處理請求,並把請求的結果,也就是HTML傳送到客戶瀏覽器.

HttpApplication是HttpRuntime所建立的嗎? 並不是,HttpRuntime只是向HttpApplicationFactory提出請求,要求返回一個HttpApplication物件。HttpApplicationFactory在接收到請求後,會先檢查是否有已經存在並空閒的物件,如果有就取出一個HttpApplication物件返回給HttpRuntime,如果沒有的話,則要建立一個HttpApplication物件給HttpRunTime。
關於HttpApplication這個類的方法的實現,就不再一一解釋,需要了解的,在類裡面寫上一個HttpApplication單詞,然後右鍵選擇“轉到定義“,就可以看到裡面的元資料了。

從上面看出global類與HttpApplication十分緊密,其事上,global類是繼承與System.Web.HttpApplication類。

複製程式碼 publicclass Global : System.Web.HttpApplication
    {

        
protectedvoid Application_Start(object sender, EventArgs e)
        {

        }
        
//省略    } 複製程式碼


假設在global類中定義變數與物件,我們在全域性中是否能夠取得或設定他的值呢?看下面的例子:


publicclass Global : System.Web.HttpApplication
    {
        
publicstaticstring UserName ="James Lee";
        
protectedvoid Application_Start(object sender, EventArgs e)
        {

        }
        
//省略    }

在頁面中設定:
WebApp.Global.UserName = "AAAA";
在設定前與設定後輸出,你可以看到值的變化,但對變數的設定,會出現什麼問題?這些就需要你在開發中去考慮了。

如果使用過MVC框架開發的朋友就很熟其路由規則配置,其實就是設定在Global類的Application_Start事件中,如下面:

複製程式碼 publicclass MvcApplication : System.Web.HttpApplication
    {
        
publicstaticvoid RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute(
"{resource}.axd/{*pathInfo}");

            routes.MapRoute(
                
"UpcomingDinners",
                
"Dinners/Page/{page}",
                
new { controller ="Dinners", action ="Index" }
            );

            routes.MapRoute(
                
"Default",                                              // Route name"{controller}/{action}/{id}",                           // URL with parametersnew { controller ="Home", action ="Index", id ="" }  // Parameter defaults            );

        }

        
protectedvoid Application_Start()
        {
            RegisterRoutes(RouteTable.Routes);
        }
    }
複製程式碼


其實我們經常用的Application物件是HttpApplication類的一個屬性,至此HttpApplication已經完成,下次轉到HttpHandler流程了。
隨便談識文斷字,查閱大量的資料,等於收集整理加上自己的見解吧,且當成長過程中的回憶。