《ASP.NET本質論》HTTP請求處理程序

        處理程序
        在ASP.NET中,所有的請求都要經過HttpApplication管道的處理,但是,請求的內容確實多種多樣的。因此,在HttpApplication的處理管道中,適合處理針對所有請求的通用處理,比如檢查當前請求的用戶身份等,並不適合直接處理情求的內容並返回處理的結果。針對不同請求的不同處理,在ASP.NET中通過各種處理程序來分別進行處理。通常情況下,根據請求的擴展名來確定適用的處理程序,根據常見的請求類型,在ASP.NET中已經與定義了許多的處理程序。

      處理程序與HttpApplication的關係
        在ASP.NET中,請求的真正處理是在處理程序這個環節,那麼,HttpApplication的作用是什麼呢?我們可以將它看作請求到達處理程序和離開處理程序的一個管道,這個管道提供了統一處理所有請求的機制,使得我們可以在請求被真正處理之前和處理之後進行預處理和處理後的工作,在有些網站處理技術中,被稱爲過濾器(Filter)。ASP.NET通過大量的HttpApplication事件,這些事件按照固定的次序依次處罰,使得我們可以方便地開發出針對請求不同處理環節的過濾器。
     而處理程序則負責完成實際的請求處理工作,對於網站開發程序員來說,大多數的開發工作是圍繞着處理程序展開的。實際上,接觸到HttpApplication事件處理的時候並不多,處理程序在不同的網站開發技術中,有着不同的名稱,在ASP.NET中,稱爲HttpHandler。
   
    處理程序接口IHttpHandler 和 IHttpAsyncHandler
     在ASP.NET中,所有的處理程序類必須實現IHttpHandler接口或者實現 IHttpAsyncHandler接口,這兩個接口的區別是前者是一個同步接口,後者是一個異步處理模式的接口。這兩個接口都定義在命名空間System.Web下。IHttpHandler的定義如下:

public interface IHttpHandler
{
    void ProcessRequest(HttpContext context);
    bool IsReusable { get; }
}

       ProcessRequest是這個接口的主要方法,接受一個HttpContext類型的請求上下文對象,通過這個對象,處理程序可以得到關於處理請求所需的信息,通過這個參數的Response屬性可以得到管理迴應的對象,用以向客戶端返回服務器處理的結果。
       IsResuable屬性表示當這個處理程序對象在使用之後,是否還可以被緩存起來,在以後的請求處理中再次使用,這個屬性主要用來配合處理程序工廠使用。

       在處理程序中使用會話
        處理程序是ASP.NET網站中處理請求的基本單位,在默認情況下,處理程序中,甚至不能使用會話狀態,這樣可以提高網站處理的速度。對於需要讀寫會話狀態的處理程序,必須實現一個特定的接口IRequiresSessionState,這個接口定義在命名空間System.Web.SessionState中,其中沒有定義任何成員,所以實現這個接口並不需要在類中增加任何成員。與此類似,同樣定義在這個命名空間下的接口 IReadOnlySessionState 也沒有定義任何成員,用來標識只需讀取會話狀態的處理程序。
       這種沒有任何成員的接口,通常被稱爲標記接口,由於在.NET中類只有單繼承,但是可以實現多個接口,所以在.NET開發早期的時候出現過一些通過標記接口來表示類的某些特徵的開發技巧。但是.NET平臺上提供了一個更加直接簡單的技術來解決這種問題,這就是標籤(Attribute),所以,這種用法曇花一現,現在很少出現。在ASP.NET開發中,這是僅有的一例。

        處理程序工廠
       實現了處理程序接口的類就可以被用來創建程序程序對象直接使用,如果再配合一個處理程序工廠,那麼就可以實現處理程序對象的管理。比如說,創建一個處理程序對象池,就可以不同在每次使用處理程序的時候創建一個新的對象,而是可以從池中取一個現有的對象直接使用,以提高效率。
       在ASP.NET中,作爲處理程序工廠的類必須實現接口IHttpHandlerFactory,這個接口定義在命名空間System.Web下,其完整定義如下:
   
public interface IHttpHandlerFactory
{
    IHttpHandler GetHandler(
        HttpContext context,
        string requestType,
        string url,
        string pathTranslated
    );

    void ReleaseHandler( IHttpHandler handler);
}
      其中 GetHandler方法用來通過這個處理工廠獲取一個處理對象,ReleaseHandler方法用來釋放一個處理程序對象


       註冊處理程序
      每一種處理程序用來處理一類的請求,不同的請求類別通過請求的擴展名來進行區分,處理程序與請求之間的匹配關係在網站的配置文件web.config中通過配置參數進行設置。system.web配置元素的子元素 httpHandlers 用來配置網站所使用的處理程序。httpHandlers元素可以包含三種子元素:add、remove、clear。

     add子元素有三個必選的屬性,作用如下:
     verb 通過一個逗號(,)分隔的HTTP請求類型列表來表示處理請求的類型,例如GET,POST等;使用型號(*)表示處理所有類型的請求。
     path 通過一個固定的URL路徑或者一個使用型號(*)的通配符來匹配請求的URL,例如,使用*.aspx表示這個處理程序將處理所有擴展名爲aspx的請求。
     type 處理程序 的類型名稱,或者是處理程序工廠的類型名稱,這個類型必須是類型的全名,如果類定義在一個命名空間中,那麼必須包含這個命名空間,如果定義在一個私有的應用程序集中,那麼必須在類名之後,通過附加一個逗號(,)分隔的程序集名稱,這個程序集的擴展名可以省略
     validate爲可選的屬性,如果設置爲false,那麼ASP.NET在第一次匹配的請求調用之前將不會試圖加載這個類。

      例如,如果我們定義了一個處理程序類這個類定義在命名空間 MyHandler 下,名爲 ValidateCodeHandler,這個類定義在私有程序集 MyHandler.dll , 用來處理GET類型的請求,請求的擴展名爲vc,那麼配置參數將如下所示:

 <httpHandlers>
        <add verb="GET" path="*.vc" type="MyHandler.ValidateCodeHandler,MyHandler"/>
      </httpHandlers>

在網站應用程序運行的時候,實際得到的配置文件來自於系統能夠的machine.config,系統的web.config 和網站自身的web.config合併,系統的配置文件位於一個特殊的文件夾下,在ASP.NET 4.0 下,這個位置可以如下表示:
  %systemroot%\Microsoft.NET\Framework\v4.0.30319\Config
在web.config中ASP.NET已經預先配置了57中處理程序的映射,程序員可以通過處理程序接口擴展自定義的處理程序。

        使用處理程序生成驗證碼

1)創建一個類庫項目 MyHandler,這個項目的默認命名空間也是 MyHandler
2)類庫項目MyHandler中添加一個新類ValidateCodeHandler,實現IHttpHandler接口,爲了在處理程序中使用Session狀態管理,同時實現IRequiresSessionState接口。
3)在ProcessRequest方法中完成驗證碼生成的操場。
4)在網站項目中引用類庫項目。
5)在網站配置文件web.config中註冊這個處理程序。
6)在需要驗證碼的頁面上使用處理程序生產的驗證碼。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;


namespace MyHandler
{
    class ValidateCodeHandler:System.Web.IHttpHandler,
        System.Web.SessionState.IRequiresSessionState
    {
        private static System.Random random = new Random();


        #region IHttpHandler 成員

        public bool IsReusable
        {
            get { throw new NotImplementedException(); }
        }

        public void ProcessRequest(HttpContext context)
        {
            context.Response.ContentType = "image.jpeg";

            System.Drawing.Image image = new System.Drawing.Bitmap(60, 30);

            //生產隨機數
            int code = random.Next(100, 10000);
            string codeString = code.ToString();

            //使用會話狀態
            context.Session["Code"] = codeString;

            using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(image))
            {
                g.Clear(System.Drawing.Color.WhiteSmoke);
                System.Drawing.StringFormat sf
                    = new System.Drawing.StringFormat();
                sf.Alignment = System.Drawing.StringAlignment.Center;
                sf.LineAlignment = System.Drawing.StringAlignment.Center;
                g.DrawString(
                    codeString,
                    new System.Drawing.Font("Arial",14),
                    System.Drawing.Brushes.Blue,
                    new System.Drawing.RectangleF(0,0,
                        image.Width,image.Height),
                        sf
                    );
            }
            context.Response.ContentType = "image/jpeg";
            image.Save(
                context.Response.OutputStream,
                System.Drawing.Imaging.ImageFormat.Jpeg
                );
        }

        #endregion
    }
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章