基于事件的異步模式(EAP模式)
基于事件的C#異步程式設計模式是比IAsyncResult模式更進階的一種異步程式設計模式,也被用在更多的場合。該異步模式具有以下優點:
· “在背景”執行耗時任務(例如下載下傳和資料庫操作),但不會中斷您的應用程式。
· 同時執行多個操作,每個操作完成時都會接到通知(在通知中可以區分是完成了哪個操作)。
· 等待資源變得可用,但不會停止(“挂起”)您的應用程式。
· 使用熟悉的事件和委托模型與挂起的異步操作通信。
實作 了EAP模式的最典型元件是WebClient。
WebClient定義了以下兩個同步方法用于從WEB上下載下傳檔案:
public void DownloadFile(string address, string fileName);
public void DownloadFile(Uri address, string fileName);
為了實作異步調用,WebClient又定義了另兩個對應的異步方法:
public void DownloadFileAsync(Uri address, string fileName);
public void DownloadFileAsync(Uri address, string fileName, object userToken);
EAP規定方法名以 Async 結尾的方法是異步調用方法。
上面的方法,最後一個userToken參數前面已經說明了其作用。
其實很簡單,當應用程式多次調用DownloadFileAsync方法的這個重載形式啟動多個異步下載下傳任務時,這個參數用于區分這些任務。簡單地說,userToken
是異步下載下傳任務的辨別。為每個正在執行的下載下傳任務給出唯一的辨別,是程式員的責任。
為了讓使用者中途取消任務,WebClient定義了以下方法:
public void CancelAsync();
由于任務可以被取消,是以問題産生了:異步調用方法啟動以後,調用者如何知道任務是正常結束還是被中途取消的?
答案很簡單:異步調用任務結束時,實作 了EAP的元件會激發一個相應的事件。以WebClient為例,當DownloadFileAsync方法啟動的異步下載下傳任務結束時,它會激發以下事件:
public event AsyncCompletedEventHandler DownloadFileCompleted;
這一事件有一個 AsyncCompletedEventArgs 類型的參數,其中包含了重要的資訊:
public class AsyncCompletedEventArgs : EventArgs
{
public bool Cancelled { get; } //該值訓示異步操作是否已被取消。
public Exception Error { get; }//該值訓示異步操作期間發生的錯誤。
public object UserState { get; }//擷取異步任務的唯一辨別符,如果使用者在啟動本任務時設定了任務辨別,則此屬性值就是這個辨別
}
由此可見,隻需在 DownloadFileCompleted事件的響應方法中檢查一下事件參數的Cancelled屬性,如果其值等于 true,就知道任務被中途取消了。
如果error屬性不為null,則任務執行過程中一定引發了異常。上述兩個條件都不滿足時,則任務是順利完成的。
當異步任務可能要執行很長時間時,往往需要通知使用者目前工作完成的進度,為此,WebClient定義了以下事件:
public event DownloadProgressChangedEventHandler DownloadProgressChanged;
這個事件的參數中(DownloadProgressChangedEventArgs類型的對象)中包含了重要的資訊。
1. TotalBytesToReceive:要傳送的總位元組數。
2. BytesReceived:已接收的位元組數。
3.ProgressPercentage:工作完成的百分比。
掌握了以上知識,使用WebClient元件下載下傳檔案就變得非常簡單,以下是一個代碼架構:
//從Web異步下載下傳網址為FileAddress的檔案
public void DownLoadFileFromWeb(string FileAddress)
{
WebClient client = new WebClient();
//挂接下載下傳完成事件響應代碼
client.DownloadFileCompleted += client_DownloadFileCompleted;
//挂接下載下傳進度事件響應代碼
client.DownloadProgressChanged += client_DownloadProgressChanged;
//啟動異步下載下傳檔案任務
Uri uri = new Uri(FileAddress);
client.DownloadStringAsync(uri);
}
下載下傳完成事件響應代碼架構如下:
void client_DownloadFileCompleted(object sender,AsyncCompletedEventArgs e)
{
if(e.Cancelled) //使用者取消了操作
{
//處理代碼。。。。
}
if(e.Error != null) //有錯誤發生
{
//處理代碼
}
if(e.UserState != null) //取出任務辨別
{
//處理代碼
}
//其它處理代碼。。。
}
下載下傳進度事件響應代碼架構如下:
void client_DownloadProgressChanged(object sender,DownloadProgressChangedEventArgs e)
{
string info = "任務辨別:{0},總資料:{1}位元組,已下載下傳:{2}位元組,完成了{3}%。";
info = string.Format(info , e.UserState , e.TotalBytesToReceive , e.BytesReceived , e.ProgressPercentage);
//.....
}
依據前面的内容,我們可以對EAP形成以下的認識:
1.實作了EAP的元件定義 了以 Async 結尾的異步調用方法。
2.當異步調用任務結束時,會激發一個相應的事件,事件的參數包含重要的資訊。
3.實作 了EAP的元件可能會提供一個用于取消異步任務的方法。
4.實作 了EAP的元件提供一個向使用者報告進度的事件。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Net;
using System.ComponentModel;
namespace ConsoleApplication1
{
public class EventAsyncModel
{
//從Web異步下載下傳網址為FileAddress的檔案
public void DownLoadFileFromWeb(string FileAddress)
{
WebClient client = new WebClient();
//挂接下載下傳完成事件響應代碼
client.DownloadFileCompleted += client_DownloadFileCompleted;
//挂接下載下傳進度事件響應代碼
client.DownloadProgressChanged += client_DownloadProgressChanged;
//啟動異步下載下傳檔案任務
Uri uri = new Uri(FileAddress);
client.DownloadFileAsync(uri,@"C:\QQ.EXE");
}
void client_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
if (e.Cancelled) //使用者取消了操作
{
//處理代碼。。。。
Console.WriteLine("cancel");
}
if (e.Error != null) //有錯誤發生
{
//處理代碼
Console.WriteLine("發生錯誤" + e.Error.ToString());
}
if (e.UserState != null) //取出任務辨別
{
//處理代碼
Console.WriteLine("任務狀态" + e.UserState.ToString());
}
//其它處理代碼。。。
Console.WriteLine("下載下傳結束呢");
}
void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
string info = "任務辨別:{0},總資料:{1}位元組,已下載下傳:{2}位元組,完成了{3}%。";
info = string.Format(info, e.UserState, e.TotalBytesToReceive, e.BytesReceived, e.ProgressPercentage);
Console.WriteLine(info);
}
}
}