httpHandlers與Http處理程序

ASP.NET HTTP 處理程序是響應對 ASP.NET Web 應用程序的請求而運行的過程(一般稱爲"終結點")。最經常使用的處理程序是處理 .aspx 文件的 ASP.NET 頁處理程序。用戶請求 .aspx 文件時,頁經過頁處理程序來處理請求。 html

ASP.NET 頁處理程序僅僅是一種類型的處理程序。ASP.NET 還包括其餘幾種內置的處理程序,例如用於 .asmx 文件的 Web 服務處理程序。 web

若是您須要進行特殊處理(能夠在應用程序中使用文件擴展名進行標識),能夠建立自定義 HTTP 處理程序。例如,下面的方案就很好地利用了自定義 HTTP 處理程序: 數據庫

  • RSS 源   若要爲站點建立 RSS 源,能夠建立一個可發出 RSS 格式 XML 的處理程序。而後將您應用程序中的 .rss 擴展名(舉例)綁定到此自定義處理程序。當用戶向站點發送以 .rss 結尾的請求時,ASP.NET 將調用您的處理程序來處理請求。
  • 圖像服務器   若是但願 Web 應用程序可以提供不一樣大小的圖像,能夠編寫一個自定義處理程序來調整圖像大小,而後將調整後的圖像做爲處理程序的響應返回給用戶。

HTTP 處理程序能夠訪問應用程序上下文,包括請求用戶的標識(若是已知)、應用程序狀態和會話信息等。當請求 HTTP 處理程序時,ASP.NET 將調用相應處理程序上的 ProcessRequest 方法。處理程序的 ProcessRequest 方法建立一個響應,此響應隨後發送回請求瀏覽器。就像任何頁請求那樣,響應將途經訂閱了處理程序運行後所發生事件的全部 HTTP 模塊。有關處理 Web 服務器請求的更多信息,請參見 ASP.NET 應用程序生命週期概述瀏覽器

HTTP 處理程序能夠是同步的也能夠是異步的。同步處理程序在完成對爲其調用該處理程序的 HTTP 請求的處理後纔會返回。異步處理程序運行進程的行爲與向用戶發送響應無關。當您須要啓動一個可能耗費很長時間的應用程序進程,而用戶又無需等候進程完成以便從服務器獲取響應時,異步處理程序很是有用。 緩存

ASP.NET 中的內置 HTTP 處理程序 服務器

ASP.NET 根據文件擴展名將 HTTP 請求映射到 HTTP 處理程序。每一個 HTTP 處理程序都可以處理應用程序中的單個 HTTP URL 或 URL 擴展名組。ASP.NET 包括幾種內置的 HTTP 處理程序,以下表所列。 app

處理程序異步

說明async

ASP.NET 頁處理程序 (*.aspx)性能

用於全部 ASP.NET 頁的默認 HTTP 處理程序。

Web 服務處理程序 (*.asmx)

用於使用 ASP.NET 建立的 Web 服務頁的默認 HTTP 處理程序。

ASP.NET 用戶控件處理程序 (*.ascx)

用於全部 ASP.NET 用戶控件頁的默認 HTTP 處理程序。

跟蹤處理程序 (trace.axd)

顯示當前頁跟蹤信息的處理程序。有關詳細信息,請參見如何:使用跟蹤查看器查看 ASP.NET 跟蹤信息

如上面配置所示,.NET Framework配置中添加的Handler,實際後面還跟了一堆,不過都是同一種HttpFrobiddenHandler

建立自定義 HTTP 處理程序

若要建立一個自定義 HTTP 處理程序,能夠建立一個可實現 IHttpHandler 接口的類以建立同步處理程序,或者建立一個可實現 IHttpAsyncHandler的類以建立異步處理程序。兩種處理程序接口都要求您實現 IsReusable 屬性和 ProcessRequest 方法。IsReusable 屬性指定 IHttpHandlerFactory對象(實際調用適當處理程序的對象)是否能夠將您的處理程序放置在池中,而且從新使用它們以提升性能,或是否在每次須要處理程序時都必須建立新實例。ProcessRequest 方法負責實際處理單個 HTTP 請求。

建立文件擴展名

建立一個類文件做爲您的 HTTP 處理程序時,可讓您的處理程序響應還沒有在 IIS 和 ASP.NET 中映射的任何文件擴展名。例如,若是您在建立用於生成 RSS 源的 HTTP 處理程序,則能夠將處理程序映射到擴展名 .rss。爲了讓 ASP.NET 知道哪一個處理程序將用於您的自定義文件擴展名,必須在 IIS 中將處理程序類文件的擴展名映射到 ASP.NET,而且在您的應用程序中將該擴展名映射到您的自定義處理程序。

默認狀況下,ASP.NET 爲自定義 HTTP 處理程序映射文件擴展名 .ashx 的方式與將擴展名 .aspx 映射到 ASP.NET 頁處理程序的方式相同。所以,若是您建立具備文件擴展名 .ashx 的 HTTP 處理程序類,該處理程序將自動註冊到 IIS 和 ASP.NET。

若是想要爲您的處理程序建立自定義文件擴展名,則必須顯式將該擴展名註冊到 IIS 和 ASP.NET。不使用文件擴展名 .ashx 的好處是您的處理程序隨後能夠從新用於其餘擴展名映射。例如,在某個應用程序中,您的自定義處理程序可能響應以 .rss 結尾的請求,而在另外一個應用程序中,您的自定義處理程序可能響應以 .feed 結尾的請求。再舉一例,您的處理程序可能映射到同一應用程序中的兩個文件擴展名,但可能基於擴展名建立兩個不一樣的響應。

下面經過一個例子來演示httpHandler的創建,註冊以及效果

在App_Code中添加類ApkHandler實現接口IHttpHandler

 

namespace FastDoge.Study
{
    public class ApkHandler : IHttpHandler
    {

        public void ProcessRequest(HttpContext context)
        {
            HttpRequest Request = context.Request;
            HttpResponse Response = context.Response;
            // This handler is called whenever a file ending 
            // in .sample is requested. A file with that extension
            // does not need to exist.
            Response.Write("<html>");
            Response.Write("<body>");
            Response.Write("<h1>Hello from a synchronous custom HTTP handler.</h1>");
            Response.Write("</body>");
            Response.Write("</html>");
        }
        public bool IsReusable
        {
            // To enable pooling, return true here.
            // This keeps the handler in memory.
            get { return false; }
        }
    }
}

 

 

 

接着到Web.config中註冊Hanler,這裏對於兩個不一樣版本的IIS也會有出入

在 IIS 6.0 和 IIS 7.0 經典模式下運行的Web.config添加如下配置

    <httpHandlers>
      <add verb="*" path="*.apk" 
        type="FastDoge.Study.ApkHandler" />
    </httpHandlers>

 

verb指定謂詞列表能夠是逗號分隔的 HTTP 謂詞列表(例如,"GET, PUT, POST"),也能夠是開始腳本映射(如星號 [*] 通配符)。

path:指定路徑屬性能夠包含單個 URL 路徑或簡單的通配符字符串(如 *.aspx)。

type:指定逗號分隔的類/程序集組合。ASP.NET 首先在應用程序的專用 \bin 目錄中搜索程序集 DLL,而後在系統程序集緩存中搜索程序集 DLL。

IIS7集成模式配置以下

  <system.webServer>
    <handlers>
      <add name="ApkHandler" verb="*"
        path="*.apk"
        type="FastDoge.Study.ApkHandler"
        resourceType="Unspecified" />
    </handlers>
  </system.webServer>

 

在運行後在瀏覽器中輸入一個以apk爲後綴的url

在MSDN中提到的能夠在IIS中經過圖形界面註冊,這裏就不嘗試了,可參考https://msdn.microsoft.com/zh-cn/library/bb515343(v=vs.100).aspx。固然若是不在配置文件中添加,要是在HttpModule中指定,要與HttpModule耦合在一塊兒的話就如上篇所說調用HttpContext.RemapHandler方法,如在上篇提到的MyModule類中做如下改動

        private void Application_BeginRequest(Object source,
        EventArgs e)
        {
            HttpApplication application = (HttpApplication)source;
            HttpContext context = application.Context;
            context.Response.Write("<h1><font color=red>" +
                "HelloWorldModule: Beginning of Request" +
                "</font></h1><hr>");

            string filePath = context.Request.FilePath;
            string fileExtension =
                VirtualPathUtility.GetExtension(filePath);
            if (fileExtension.Equals(".apk", StringComparison.InvariantCultureIgnoreCase) &&
                 context.Request.HttpMethod.Equals("GET"))
            {
                context.RemapHandler(new ApkHandler());
            }
        }

 

去掉Web.config的配置,訪問以上URL有一樣的效果。

   

異步 HTTP 處理程序

利用異步 HTTP 處理程序能夠啓動一個外部進程(例如對遠程服務器的方法調用),而後繼續處理程序的處理工做,而無需等待外部進程結束。在異步 HTTP 處理程序的處理期間,ASP.NET 將一般用於外部進程的線程放回線程池中,直處處理程序收到來自外部進程的回調。這樣能夠避免阻止線程,並大幅改善了性能,由於一次所能執行的線程數量是有限的。若是許多用戶都在請求依賴於外部進程的同步 HTTP 處理程序,那麼操做系統可能很快就會用完全部線程,由於大量線程被阻止,正在等待外部進程。

建立異步處理程序時,除了實現 IHttpAsyncHandler 接口,還必須實現 BeginProcessRequest 以啓動異步調用來處理單個 HTTP 請求。還必須實現 EndProcessRequest 方法,以便在進程結束時運行清理代碼。

下面則定義了一個AsyncApkHandler的異步處理程序,在BeginProcessRequest時調用一個AsynchOperation,該類實現IAsyncResult接口,須要異步操做的代碼在方法StartAsyncWork()中調用

 

namespace FastDoge.Study
{
    public class AsyncApkHandler : IHttpAsyncHandler
    {
        public bool IsReusable { get { return false; } }

  
        public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData)
        {
            context.Response.Write("<p>Begin IsThreadPoolThread is " + Thread.CurrentThread.IsThreadPoolThread + " " + DateTime.Now + "  " + Thread.CurrentThread.ManagedThreadId + "</p>\r\n");
            AsynchOperation asynch = new AsynchOperation(cb, context, extraData);
            asynch.StartAsyncWork();
            return asynch;
        }

        public void EndProcessRequest(IAsyncResult result)
        {
            if (result is AsynchOperation)
            {
                (result as AsynchOperation).Context.Response.Write("<p>End IsThreadPoolThread is " + Thread.CurrentThread.IsThreadPoolThread + "  "+DateTime.Now+"  " + Thread.CurrentThread.ManagedThreadId + "</p>\r\n");
            }
        }

        public void ProcessRequest(HttpContext context)
        {
            throw new InvalidOperationException();
        }
    }

    class AsynchOperation : IAsyncResult
    {
        private bool _completed;
        private Object _state;
        private AsyncCallback _callback;
        private HttpContext _context;

        bool IAsyncResult.IsCompleted { get { return _completed; } }
        WaitHandle IAsyncResult.AsyncWaitHandle { get { return null; } }
        Object IAsyncResult.AsyncState { get { return _state; } }
        bool IAsyncResult.CompletedSynchronously { get { return false; } }

        public HttpContext Context
        {
            get
            {
                return _context;
            }
        }

        public AsynchOperation(AsyncCallback callback, HttpContext context, Object state)
        {
            _callback = callback;
            _context = context;
            _state = state;
            _completed = false;
        }

        public void StartAsyncWork()
        {
            ThreadPool.QueueUserWorkItem(new WaitCallback(StartAsyncTask), null);
        }

        private void StartAsyncTask(Object workItemState)
        {
            Thread.Sleep(3000);
            _context.Response.Write("<p>Completion IsThreadPoolThread is " + Thread.CurrentThread.IsThreadPoolThread + "  " + DateTime.Now + " " + Thread.CurrentThread.ManagedThreadId + "</p>\r\n");

            _context.Response.Write("Hello World from Async Handler!");
            _completed = true;
            _callback(this);
        }
    }
}

 

 

配置方式如以前的方式。效果以下

   

自定義 IHttpHandlerFactory 類

IHttpHandlerFactory 類接收請求並負責向相應的 HTTP 處理程序轉發請求。您能夠經過建立一個實現了 IHttpHandlerFactory 接口的類來建立自定義 HTTP 處理程序工廠。建立自定義處理程序工廠能夠更好地控制對 HTTP 請求的處理,由於這樣能夠基於運行時條件建立不一樣的處理程序。例如,使用自定義 HTTP 處理程序工廠,能夠在 HTTP 請求方法爲 PUT 時爲某個文件類型實例化一個 HTTP 處理程序,而在該方法爲 GET 時實例化另外一個 HTTP 處理程序。又例如,經過使用 HTTP 處理程序工廠,能夠建立有限數量的 HTTP 處理程序對象,來訪問諸如數據庫鏈接等昂貴或有限的資源。而後,能夠在之後的請求中重用這些處理程序對象。

IHttpHandlerFactory 有兩個方法

IHttpHandler GetHandler返回實現 System.Web.IHttpHandler 接口的類的實例

void ReleaseHandler使工廠能夠重用現有的處理程序實例。

下面則定義個ApkHanlderFactory,同時在ApkHandler 輸出的內容上有稍做修改(輸出當前HttpHandler的HashCode)

 

namespace FastDoge.Study
{
    public class ApkHanlderFactory : IHttpHandlerFactory
    {
        private ApkHandler _cacheHandler;

        private ApkHandler CacheHandler
        {
            get
            {
                if (_cacheHandler == null)
                {
                    _cacheHandler = new ApkHandler();
                }
                return _cacheHandler;
            }
        }

        public IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated)
        {
            if (context.Request.QueryString.AllKeys.Contains("IsCache") &&
                context.Request["IsCache"].ToLower().Equals("true", StringComparison.InvariantCultureIgnoreCase))
            {
                return CacheHandler;
            }
            return new ApkHandler();
        }

        public void ReleaseHandler(IHttpHandler handler)
        {
            
        }
    }
}

 

 

配置文件方面與註冊IHttpHandler基本一致,只是type特性中填寫的是實現IHttpHandlerFactory接口的類名,可是在Module中經過編碼的形式指定的方式暫時沒找到,估計須要看源碼了。

請求URL以下URL時,響應的html內容一直不變

若是去除IsCache參數時,內容則每次都在變化。

   

   

參考內容

HTTP 處理程序介紹

來自 <https://msdn.microsoft.com/zh-cn/library/ms227675(v=vs.100).aspx>

HTTP 處理程序和 HTTP 模塊概述

來自 <https://msdn.microsoft.com/zh-cn/library/bb398986(v=vs.100).aspx>

相關文章
相關標籤/搜索