一、前言
1.對讀者想說的話:(可跳過)
在此我感謝那些看了《ASP.NET 之 自定義 同步HTTP處理程序》這篇文章以及看到了這篇《ASP.NET 之 自定義 異步HTTP處理程序》的親們。前面的那篇可能看過MSDN的親們一定會發現很多熟悉的地方。而我其實就是比較詳細的介紹了一下,讓大家更好的理解
PS:MSDN從頭到尾都是文字且文字很統一,恐怕很多人都感覺畏懼,懶的去看,所以我將其重要的部分提取出來,使用易懂的例子和簡潔的語言來敘述。當然其中也免不了錯誤,希望各位親們可以指出。
2.正式的開始
前面我們學習了關於關於自定義同步HTTP處理程序,相信大家可能感覺有所成就(大牛們可能會覺得so easy)。但是這種同步的機制只能對付客戶訪問較少的情況或者數據處理量不大的情況(每次申請一個同步HTTP處理程序都會新建一個新的線程來處理,當申請量很大時,線程將會被堵塞,致使服務器性能低下,甚至宕機)。而今天這篇文章就是解決同步HTTP處理程序的這個致命缺點,有效的使用服務器的資源。
PS:異步(僅限在本文章下的情況): 簡單來說就是一部分操作在使用我們自己創建的線程,另一部分操作由操作系統調用自身的線程有條不紊的處理,這樣我們可以將簡單的處理由我們自身的線程完成,而復雜的處理則交給系統管理的線程來處理。因為這些線程是系統管理的所以不會出現卡死的情況,系統內部會自動的管理。當然系統會通過通知的方式告知我們的自己的線程該處理已經完成,這樣我們就可以避免使用多線程技術,卻難於管理的問題。
以下為圖例:
二、注冊與綁定(雖然前一篇已經講述過,但是在這里仍然重新再講一次)
為什么要有這兩部呢?而且還是要注冊與綁定這兩個呢?
答案是 你只寫一個類 vs是不可能知道你這個東西是干什么的,所以我們需要在 web.config 中注冊我們自定義的HTTP處理程序。而綁定則是讓iis知道我們這個站點中含有一個自定義的HTTP處理程序。(下面我將以 iis7 為例說明如何綁定)
1.注冊
1 <configuration> 2 <system.web> 3 <httpHandlers> 4 <add verb="*" path="<!-- 這里寫需要綁定的客戶端申請的頁面(*.smm,*.ffs,web1.ffe) -->" type="<!-- 這里寫處理程序的類名 -->" 5 </httpHandlers> 6 </system.web> 7 </configuration>
以上需要自行編寫的部分我都已使用注釋寫好
2.綁定( iis7 )
1) 打開 iis7 -》 打開 網站 節點 -》 點擊你的網站的名稱
2) 雙擊
3) 點擊
4)
5) 最后點擊 確定 這樣在 iis 中的綁定就完成了(后面的完整例子我將會以文字介紹該過程)
三、關於類的實現
這里我們將要實現兩個接口的功能,下面我將分開來闡述
1. IHttpAsyncHandler 接口
需實現方法以及屬性如下:
- IAsyncResult BeginProcessRequest( HttpContext context , AsyncCallback cb , Object extradata )
啟動對HTTP處理程序的異步調用
參數說明:
context : 該對象提供對用於向 HTTP 請求提供服務的內部服務器對象(如 Request、Response、Session 和 Server)的引用。
cb : 當異步操作完成后調用該委托告知我們操作已經完成
extradata : 處理該請求所需的所有額外數據
返回值:
返回有關進程狀態的IAsyncResult (可以讓我們時刻查看異步調用中的當前狀態) - void EndProcessRequest( IAsyncResult result )
進程結束時提供異步處理End方法
參數說明:
result : 有關進程狀態的IAsyncResult(這里的result跟BeginProcessRequest返回的是同一個對象,只是內部的屬性等等改變了)
注: 但是我們還要實現不在IHttpAsyncHandler接口中的一個屬性和一個方法,否則IIS會報錯
- bool IsRusable
表明是否使用池,只需要實現get,返回false表示不使用,返回true表示使用。 - void ProceessRequest( HttpContext context )
同步HTTP處理程序被調用的方法(這里並不會調用該方法,但是必須實現)
2. IAsyncResutl 接口
需實現方法以及屬性如下:
- Object AsyncState
獲取用戶定義的對象(其實就是以上的 extradata 並且只要實現get ) - WaitHandler AsyncWaitHandle
獲取用於等待異步操作完成的 WaitHandle (一般都是返回NULL 並且只要實現get ) - bool CompletedSynchronously
獲取異步操作是否同步完成的指示(一般都是返回false) - bool IsCompleted
獲取異步操作是否已完成的指示
四、實現該功能(iis7 / asp.net 4.0 / vs2010 / windows 7 64bit )
注: 1.新建空web項目,並添加 App_Code 文件夾,並部署在 iis 上
2.在App_Code中新建一個類,命名為"AsyncRequestHandler.cs"(這里的命名不影響,但是類名是關鍵)
3.在 AsyncRequestHandler.cs 中引用 "System.Threading" 命名空間
下面我們將一步一步的學習實現這個功能,雖然只是一個很簡單的例子,但是可以讓你在以后的開發中更加靈活的運用。
1. 實現 IHttpAsyncHandler 接口
代碼如下:
1 public class AsyncHttpHandler : IHttpAsyncHandler 2 { 3 public AsyncHttpHandler() 4 { 5 // 6 //TODO: 在此處添加構造函數邏輯 7 // 8 } 9 10 public bool IsReusable 11 { 12 get 13 { 14 return false; //表明不使用池 15 } 16 } 17 18 public void ProcessRequest(HttpContext context) //不調用 必須實現的方法 19 { 20 throw new InvalidOperationException(); 21 } 22 23 /// <summary> 24 /// 當客戶申請時執行的異步處理 25 /// </summary> 26 /// <param name="context">包含httpresponse、httprequest、server對象</param> 27 /// <param name="cb">回調函數</param> 28 /// <param name="extradata">需要傳遞的參數</param> 29 /// <returns>返回有關進程的狀態信息</returns> 30 public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extradata) // 必須實現的方法 31 { 32 context.Response.Write("<p>AsyncHttpHandler</p>"); //向頁面中寫入html表明是該信息來自何處 33 AsyncOperation op = new AsyncOperation(context, cb, extradata); //實例化實現了 IAsyncResult 接口的類(主要實現異步處理的類) 34 op.StartAsyncWork(); //開始異步處理 35 return op; //返回該對象 36 } 37 38 /// <summary> 39 /// 當BeginProcessRequest中的 return op;與異步的處理完成后調用(調用完既呈現頁面) 40 /// </summary> 41 /// <param name="result">為op,但是屬性已改變</param> 42 public void EndProcessRequest(IAsyncResult result) 43 { 44 } 45 }
2.實現 IAsyncResult 接口(與上面的代碼在同一個文件中)
代碼如下:
1 public class AsyncOperation : IAsyncResult 2 { 3 HttpContext _context; //保存context的引用 4 AsyncCallback _cb;//保存回調委托的引用 5 object _state;//保存額外的信息 6 bool _iscomplate;//保存異步操作是否完成 7 8 /// <summary> 9 /// 構造函數,將AsyncHttpHandler的參數全部傳遞進來 10 /// </summary> 11 /// <param name="context"></param> 12 /// <param name="cb"></param> //該回調不可被重寫,否則將會出現客戶端永久等待的狀態 13 /// <param name="state"></param> //構造時該值可以傳遞任意自己需要的數據 14 public AsyncOperation(HttpContext context, AsyncCallback cb, object state) 15 { 16 _context = context; 17 _cb = cb; 18 _state = state; 19 _iscomplate = false; //表明當前異步操作未完成 20 } 21 22 /// <summary> 23 /// 實現獲得當前異步處理的狀態 24 /// </summary> 25 bool IAsyncResult.IsCompleted 26 { 27 get 28 { 29 return _iscomplate; 30 } 31 } 32 33 /// <summary> 34 /// 返回 false 即可 35 /// </summary> 36 bool IAsyncResult.CompletedSynchronously 37 { 38 get 39 { 40 return false; 41 } 42 } 43 44 /// <summary> 45 /// 將返回額外的信息 46 /// </summary> 47 object IAsyncResult.AsyncState 48 { 49 get 50 { 51 return _state; 52 } 53 } 54 55 /// <summary> 56 /// 為空 57 /// </summary> 58 WaitHandle IAsyncResult.AsyncWaitHandle 59 { 60 get 61 { 62 return null; 63 } 64 } 65 66 /// <summary> 67 /// 表明開始異步處理的主函數(方法名可以改,但上面的調用也需要一起改) 68 /// </summary> 69 public void StartAsyncWork() 70 { 71 ThreadPool.QueueUserWorkItem(new WaitCallback(StartAsyncTask), null);//相信很多玩國.net winform 開發的一定認識 72 } 73 74 /// <summary> 75 /// 異步操作調用的方法 76 /// </summary> 77 /// <param name="workstate">為QueueUserWorkItem方法中第二個參數傳遞的值</param> 78 public void StartAsyncTask(object workstate) 79 { 80 _context.Response.Write("<p>Completion IsThreadPoolThread is" + Thread.CurrentThread.IsThreadPoolThread + "</p>"); 81 _iscomplate = true; //表明異步操作已完成 82 _cb(this);//調用回調函數表明完成 83 } 84 }
3.web.config 配置
內容如下(紅色方框部分為需要添加的內容):
4.iis綁定(如何綁定見 二 )
5.測試
時你隨意的寫 test.async 或者 asd.async 等等,最后呈現的頁面都是一致的。這樣就達到我們的效果了
五、看完這些只是淺層
這里我想指明的是看完這些並不代表你已經掌握了所有,因為關於異步還有一個部分就是共享資源的使用,這個就需要使用到 WaitHandle 類,否則就會導致多個線程同時訪問並修改同一個共享資源,后果可想而知。所以在這篇文章完結的同時也意味着新的問題的開始,所以我們要不斷的學習下去。