一、前言
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.註冊
複製代碼 代碼如下:<configuration>
<system.web>
<httpHandlers>
<add verb="*" path="<!-- 這裡寫需要綁定的用戶端申請的頁面(*.smm,*.ffs,web1.ffe) -->" type="<!-- 這裡寫處理常式的類名 -->"
</httpHandlers>
</system.web>
</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 介面
代碼如下:
複製代碼 代碼如下:public class AsyncHttpHandler : IHttpAsyncHandler
{
public AsyncHttpHandler()
{
//
//TODO: 在此處添加建構函式邏輯
//
}
public bool IsReusable
{
get
{
return false; //表明不使用池
}
}
public void ProcessRequest(HttpContext context) //不調用 必須實現的方法
{
throw new InvalidOperationException();
}
/// <summary>
/// 當客戶申請時執行的非同步處理
/// </summary>
/// <param name="context">包含httpresponse、httprequest、server對象</param>
/// <param name="cb">回呼函數</param>
/// <param name="extradata">需要傳遞的參數</param>
/// <returns>返回有關進程的狀態資訊</returns>
public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extradata) // 必須實現的方法
{
context.Response.Write("<p>AsyncHttpHandler</p>"); //向頁面中寫入html表明是該資訊來自何處
AsyncOperation op = new AsyncOperation(context, cb, extradata); //執行個體化實現了 IAsyncResult 介面的類(主要實現非同步處理的類)
op.StartAsyncWork(); //開始非同步處理
return op; //返回該對象
}
/// <summary>
/// 當BeginProcessRequest中的 return op;與非同步處理完成後調用(調用完既呈現頁面)
/// </summary>
/// <param name="result">為op,但是屬性已改變</param>
public void EndProcessRequest(IAsyncResult result)
{
}
}
2.實現 IAsyncResult 介面(與上面的代碼在同一個檔案中)
代碼如下:複製代碼 代碼如下:public class AsyncOperation : IAsyncResult
{
HttpContext _context; //儲存context的引用
AsyncCallback _cb;//儲存回調委託的引用
object _state;//儲存額外的資訊
bool _iscomplate;//儲存非同步作業是否完成
/// <summary>
/// 建構函式,將AsyncHttpHandler的參數全部傳遞進來
/// </summary>
/// <param name="context"></param>
/// <param name="cb"></param> //該回調不可被重寫,否則將會出現用戶端永久等待的狀態
/// <param name="state"></param> //構造時該值可以傳遞任意自己需要的資料
public AsyncOperation(HttpContext context, AsyncCallback cb, object state)
{
_context = context;
_cb = cb;
_state = state;
_iscomplate = false; //表明當前非同步作業未完成
}
/// <summary>
/// 實現獲得當前非同步處理的狀態
/// </summary>
bool IAsyncResult.IsCompleted
{
get
{
return _iscomplate;
}
}
/// <summary>
/// 返回 false 即可
/// </summary>
bool IAsyncResult.CompletedSynchronously
{
get
{
return false;
}
}
/// <summary>
/// 將返回額外的資訊
/// </summary>
object IAsyncResult.AsyncState
{
get
{
return _state;
}
}
/// <summary>
/// 為空白
/// </summary>
WaitHandle IAsyncResult.AsyncWaitHandle
{
get
{
return null;
}
}
/// <summary>
/// 表明開始非同步處理的主函數(方法名可以改,但上面的調用也需要一起改)
/// </summary>
public void StartAsyncWork()
{
ThreadPool.QueueUserWorkItem(new WaitCallback(StartAsyncTask), null);//相信很多玩國.net winform 開發的一定認識
}
/// <summary>
/// 非同步作業調用的方法
/// </summary>
/// <param name="workstate">為QueueUserWorkItem方法中第二個參數傳遞的值</param>
public void StartAsyncTask(object workstate)
{
_context.Response.Write("<p>Completion IsThreadPoolThread is" + Thread.CurrentThread.IsThreadPoolThread + "</p>");
_iscomplate = true; //表明非同步作業已完成
_cb(this);//調用回呼函數表明完成
}
}
3.web.config 配置
內容如下(紅色方框部分為需要添加的內容):
4.iis綁定(如何綁定見 二 )
5.測試
時你隨意的寫 test.async 或者 asd.async 等等,最後呈現的頁面都是一致的。這樣就達到我們的效果了
五、看完這些只是淺層
這裡我想指明的是看完這些並不代表你已經掌握了所有,因為關於非同步還有一個部分就是共用資源的使用,這個就需要使用到 WaitHandle 類,否則就會導致多個線程同時訪問並修改同一個共用資源,後果可想而知。所以在這篇文章完結的同時也意味著新的問題的開始,所以我們要不斷的學習下去。