Asp.net本質論之應用程式物件

駑馬農夫發表於2017-10-18
主題 概要
Asp.net 應用程式物件
編輯 時間
新建 20171018
序號 參考資料
1 Asp.net本質論
2 https://msdn.microsoft.com/en-us/library/system.web.httpapplication(v=vs.110).aspx
3 https://msdn.microsoft.com/en-us/library/system.web.ihttpmodule(v=vs.110).aspx

在上一篇ASP.net本質論之用控制檯應用程式建立Asp.net伺服器
中基本理清了伺服器監聽部分及怎麼建立自己的應用程式域和處理程式。本篇對當請求到達後,asp.net如何處理的內容做一個學習總結。

針對每一次請求,ASP.net將建立一個處理這次請求所使用的HttpContext物件例項,這個物件例項將用來在ASP.net伺服器的處理過程中傳遞所有需要的引數,在請求到達Asp.net伺服器之後,這個物件將被建立出來,在一次請求處理之後,這個物件將被丟棄掉。HttpContext物件包括了HttpRequest型別的物件以表示請求引數,HttpResponse型別的物件以表示回應的處理物件,另外還有HttpServerUtility型別的物件等。

當HttpContext物件被建立之後,HttpRuntime將隨後建立一個用於處理請求的物件,這個物件的型別為HttpApplication。
在ASP.net內部,HttpRuntime管理一個定義在System.Web名稱空間下的HttpApplicationFactory類的例項,HttpApplicationFactory通過工廠模式管理HttpApplication物件,在HttpApplicationFactory內部維護了一個HttpApplication物件池,使得被建立的HttpApplication物件可以被重複使用。

處理管道

所謂的處理管道,就是處理複雜問題的時候,將處理的過程分解為多個處理步驟,我們將這種經過多個步驟的處理方式稱為處理管道。如下圖所示:
這裡寫圖片描述

這些管道步驟實際上是一系列的事件,MSDN
https://msdn.microsoft.com/en-us/library/system.web.httpapplication(v=vs.110).aspx
中詳解了這些事件。程式設計師通過編寫事件處理方法就可以自定義每一個請求的擴充套件處理過程。

那HttpApplication是怎麼樣定義這麼多事件的呢?

通過繼承System.ComponentModel.Component類,對於這個派生類所需要定義的每一個事件,在類中定義一個對應的作為key的物件,以後,通過這個key物件來訪問由Events集合管理的事件。

下面的程式碼演示了一個Mini的處理管道,沒有HttpApplication這麼多事件,但定義過程類似:

定義:

namespace Aspnet.Pipe
{
    public class ProcessPipeline:System.ComponentModel.Component
    {
        private static readonly object startEvent = new object();
        private static readonly object preProcessEvent = new object();
        private static readonly object postProcessEvent = new object();
        private static readonly object endEvent = new object();


        public event EventHandler StartEvent
        {
            add { this.Events.AddHandler(startEvent, value); }
            remove { this.Events.RemoveHandler(startEvent, value); }
        }

        public event EventHandler PreProcessEvent
        {
            add { this.Events.AddHandler(preProcessEvent, value); }
            remove { this.Events.RemoveHandler(preProcessEvent, value); }
        }

        public event EventHandler PostProcessEvent
        {
            add { this.Events.AddHandler(postProcessEvent, value); }
            remove { this.Events.RemoveHandler(postProcessEvent, value); }
        }

        public event EventHandler EndEvent
        {
            add { this.Events.AddHandler(endEvent, value); }
            remove { this.Events.RemoveHandler(endEvent, value); }
        }


        protected void OnStartProcess(EventArgs e)
        {
            if(this.Events[startEvent]!=null)
            {
                (this.Events[startEvent] as EventHandler)(this,e);
            }
        }


        protected void OnPreProcess(EventArgs e)
        {
            if (this.Events[preProcessEvent] != null)
            {
                (this.Events[preProcessEvent] as EventHandler)(this, e);
            }
        }

        protected void OnPostProcess(EventArgs e)
        {
            if (this.Events[postProcessEvent] != null)
            {
                (this.Events[postProcessEvent] as EventHandler)(this, e);
            }
        }

        protected void OnEndEvent(EventArgs e)
        {
            if (this.Events[endEvent] != null)
            {
                (this.Events[endEvent] as EventHandler)(this, e);
            }
        }


        public void Process()
        {
            Console.WriteLine("開始處理....");
            this.OnStartProcess(EventArgs.Empty);

            Console.WriteLine("準備處理....");
            this.OnPreProcess(EventArgs.Empty);

            Console.WriteLine("正在處理....");
            this.OnPostProcess(EventArgs.Empty);

            Console.WriteLine("處理完成....");
            this.OnEndEvent(EventArgs.Empty);
        }
    }
}

使用:

public static void Main()
        {

            ProcessPipeline process = new ProcessPipeline();
            process.StartEvent += new EventHandler(startProcessHandler);
            process.PreProcessEvent += new EventHandler(preProcessHandler);
            process.PostProcessEvent += new EventHandler(postProcessHandler);
            process.EndEvent += new EventHandler(endProcessHandler);

            process.Process();
        }


        public static void startProcessHandler(object sender,EventArgs e)
        {
            Console.WriteLine("開始處理的事件處理。。。。。");
        }

        public static void preProcessHandler(object sender, EventArgs e)
        {
            Console.WriteLine("預處理的事件處理。。。。。");
        }

        public static void postProcessHandler(object sender, EventArgs e)
        {
            Console.WriteLine("處理後的事件處理。。。。。");
        }

        public static void endProcessHandler(object sender, EventArgs e)
        {
            Console.WriteLine("處理完成的事件處理。。。。。");
        }

結果:

這裡寫圖片描述

處理HttpApplication的事件

程式設計師對HttpApplication的事件進行處理過程擴充套件,關鍵點是如何引用這個HttpApplication物件,因為HttpApplication物件是由Asp.net基礎架構來建立和維護的。
在ASP.net中提供了兩種方式:IHttpModule方式和global.asax方式。

通過IHttpModule建立HttpApplication事件處理程式

第一步:實現IHttpModule介面,介面說明參照MSDN:
https://msdn.microsoft.com/en-us/library/system.web.ihttpmodule(v=vs.110).aspx

並參加MSDN上的例子:
https://msdn.microsoft.com/en-us/library/ms227673(v=vs.110).aspx

第二步:註冊HttpModule
在Asp.net中,實現IHttpModule介面只是實現HttpModule的第一步,在Asp.net中所使用的HttpModule還必須在網站配置檔案中進行註冊才能真正生效,並在Asp.net中使用。

在網站的配置檔案web.config中,system.web配置元素的子元素httpModules用來配置網站所使用的HttpModule;httpModules的子元素用來增加一個新的HttpModule,clear將清除前面註冊的所有HttpModule。

Add元素有兩個必選的屬性name和type,簡介如下:

Name:表示這個HttpModule在程式中的名字,作為索引器的唯一標識。
Type:表示HttpModule物件的型別名,asp.net網站可以使用這個型別名,通過反射來動態建立HttpModule物件。如果不在同一個名稱空間,要加上程式集名稱,並用逗號分隔。

通過global.asax建立HttpApplication事件處理

在global.asax中,針對HttpApplication的事件處理,可以通過定義特殊命名的方法來實現。首先,這些方法必須符合System.EventHandler,因為所有的HttpApplication管道事件都使用這個委託定義。第二,方法的作用域必須是public。第三,方法的命名格式必須如下:
Application_註冊的事件名稱。按照這種命名方法定義在global.asax中的方法將被自動註冊到對應的事件中。

相關文章