http://dev.yesky.com/msdn/404/2387904.shtml
(一).簡單介紹實現原理
左為未使用非同步頁功能執行過程(Asp.net 1.0通常情況), 右為使用了非同步頁執行過程(Asp.net 2.0新增特性).
(Asp.net 1.0一般處理過程) (使用Asp.net 2.0新增特性非同步頁功能處理過程) |
從左圖中看出,在一個頁面整個請求的過程中, 一個線程始終為同一個頁面的請求服務.
而從右圖可以看出,在一個頁面請求的過程中, 可以由不同的線程為本頁面請求服務.
顯然,採用圖中方式在用戶端請求數量多時,網站整體效率較高. 因為:
1. 當未使用非同步頁時,一個線程只能為同一個頁面的請求服務. 即使頁面請求過程中處理其它的I/O等操作時,此線程也一直處於等待狀態. 當此頁面使用完此線程時,才將它放回到線程池. 線程數量是有限的! 所以當不使用線程時及時放回線池可以使系統效能大大提高!
2.當使用了非同步頁功能時,如右圖中,開始Thread1是為頁面服務的,但當頁面處理其它的事情(比如I/O或調用其它WebService) 時,Thread1被放回線程池, 此時Thread1可以為其它頁面請求服務了. 當此頁面執行完自己的操作回來後, Thread2接著為頁面請求服務,並不是使用的原來的線程Thread1. 這樣網站的伸縮性會更好.
(二).使用方法樣本
I. 用 Page.AddOnPreRenderCompleteAsync 實現非同步頁功能
a. Page標誌加屬性: Async="true", 添加後代碼如下:
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="AsyncPage.aspx.cs" Inherits="_Default" Async="true" %> |
b. 後台非同步頁面相關代碼 :
1private WebRequest _request; 2 protected void Page_Load(object sender, EventArgs e) 3 { 4 //註冊非同步呼叫的Begin和End方法. 5 AddOnPreRenderCompleteAsync( 6 new BeginEventHandler(BeginAsyncOperation), 7 new EndEventHandler(EndAsyncOperation) 8 ); 9 } 10 11 //非同步呼叫開始方法(當執行此方法時,當前線程就回到線程池,等待為其它請求服務). 12 IAsyncResult BeginAsyncOperation(object sender, EventArgs e, AsyncCallback cb, object state) 13 { 14 _request = WebRequest.Create("http://blog.csdn.net/chengking/"); 15 return _request.BeginGetResponse(cb, state); 16 } 17 18 //非同步呼叫結束後的接收方法(非同步作業執行完成後,會重新從線程池中取個線程為本頁面請求服務). 19 void EndAsyncOperation(IAsyncResult ar) 20 { 21 string text; 22 using (WebResponse response = _request.EndGetResponse(ar)) 23 { 24 using (StreamReader reader = new StreamReader(response.GetResponseStream())) 25 { 26 text = reader.ReadToEnd(); 27 } 28 } 29 this.lbOupput.Text = text; 30 } |
2. 資料庫物件SqlCommand實現非同步呼叫功能.
a. Page標誌加屬性: Async="true", 添加後代碼如下:
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="AsyncPage.aspx.cs" Inherits="_Default" Async="true" %> |
b. 後台代碼
1public partial class AsyncVisitDatabase : System.Web.UI.Page 2{ 3 //定義資料操作對象 4 private SqlConnection _connection; 5 private SqlCommand _command; 6 private SqlDataReader _reader; 7 8 protected void Page_Load(object sender, EventArgs e) 9 { 10 if (!IsPostBack) 11 { 12 //註冊事件Page_PreRender執行完成時執行方法 13 this.PreRenderComplete += new EventHandler(Page_PreRenderComplete); 14 15 /**////註冊非同步呼叫的Begin和End方法. 16 AddOnPreRenderCompleteAsync( 17 new BeginEventHandler(BeginAsyncOperation), 18 new EndEventHandler(EndAsyncOperation) 19 ); 20 } 21 } 22 23 //非同步呼叫開始方法(當執行此方法時,當前線程就回到線程池,等待為其它請求服務). 24 IAsyncResult BeginAsyncOperation(object sender, EventArgs e, AsyncCallback cb, object state) 25 { 26 string connect = WebConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString; 27 _connection = new SqlConnection(connect); 28 _connection.Open(); 29 _command = new SqlCommand("select * from sales", _connection); 30 return _command.BeginExecuteReader(cb, state); 31 } 32 33 //非同步呼叫結束後的接收方法(非同步作業執行完成後,會重新從線程池中取個線程為本頁面請求服務). 34 void EndAsyncOperation(IAsyncResult ar) 35 { 36 _reader = _command.EndExecuteReader(ar); 37 } 38 39 //事件Page_PreRender執行完成時執行方法,在這裡可以將非同步呼叫返回結果賦值給頁面上的控制項或者其它善後操作. 40 protected void Page_PreRenderComplete(object sender, EventArgs e) 41 { 42 GridView1.DataSource = _reader; 43 GridView1.DataBind(); 44 } 45 46 public override void Dispose() 47 { 48 if (_connection != null) 49 _connection.Close(); 50 base.Dispose(); 51 } 52} |
3. 實現非同步呼叫Webservice
a. Page標誌加屬性: Async="true", 添加後代碼如下:
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="AsyncPage.aspx.cs" Inherits="_Default" Async="true" %> |
b.後台代碼
Webservice方法(產生資料).
1public class WebService : System.Web.Services.WebService { 2 3 public WebService () { 4 5 //Uncomment the following line if using designed components 6 //InitializeComponent(); 7 } 8 9 [WebMethod] 10 public DataSet GetData() { 11 return CreateData(); 12 } 13 14 private DataSet CreateData() 15 { 16 DataTable dtTypeChild = new DataTable(); 17 dtTypeChild.Columns.Add(new DataColumn("TypeID", typeof(int))); 18 dtTypeChild.Columns.Add(new DataColumn("TypeDetail", typeof(string))); 19 //Add data 20 DataRow drChild1 = dtTypeChild.NewRow(); 21 drChild1["TypeID"] = 1; 22 drChild1["TypeDetail"] = "Apple"; 23 dtTypeChild.Rows.Add(drChild1); 24 DataRow drChild2 = dtTypeChild.NewRow(); 25 drChild2["TypeID"] = 2; 26 drChild2["TypeDetail"] = "orange"; 27 dtTypeChild.Rows.Add(drChild2); 28 DataRow drChild3 = dtTypeChild.NewRow(); 29 drChild3["TypeID"] = 3; 30 drChild3["TypeDetail"] = "banana"; 31 dtTypeChild.Rows.Add(drChild3); 32 DataRow drChild4 = dtTypeChild.NewRow(); 33 drChild4["TypeID"] = 4; 34 drChild4["TypeDetail"] = "pineapple"; 35 dtTypeChild.Rows.Add(drChild4); 36 DataRow drChild5 = dtTypeChild.NewRow(); 37 drChild5["TypeID"] = 5; 38 drChild5["TypeDetail"] = "pear"; 39 dtTypeChild.Rows.Add(drChild5); 40 dtTypeChild.TableName = "fruit"; 41 42 DataSet ds = new DataSet(); 43 ds.Tables.Add(dtTypeChild); 44 return ds; 45 } 46 47} |
後台代碼:
1public partial class AsyncVisitWebservice : System.Web.UI.Page 2{ 3 private King.WebService _ws; 4 private DataSet _ds; 5 6 protected void Page_Load(object sender, EventArgs e) 7 { 8 if (!IsPostBack) 9 { 10 this.PreRenderComplete += new EventHandler(Page_PreRenderComplete); 11 _ws = new King.WebService(); 12 _ws.GetDataCompleted += new King.GetDataCompletedEventHandler(GetDataCompleted); 13 _ws.Url = new Uri(Request.Url, "WebService.asmx").ToString(); 14 _ws.UseDefaultCredentials = true; 15 _ws.GetDataAsync(); 16 } 17 } 18 19 void GetDataCompleted(Object source, King.GetDataCompletedEventArgs e) 20 { 21 _ds = e.Result; 22 } 23 24 protected void Page_PreRenderComplete(object sender, EventArgs e) 25 { 26 this.GridView1.DataSource = _ds; 27 GridView1.DataBind(); 28 } 29 30 public override void Dispose() 31 { 32 if (_ws != null) 33 _ws.Dispose(); 34 base.Dispose(); 35 } 36} |
4. 用 PageAsyncTask 實現非同步呼叫功能(除了實現非同步功能,還可以實現非同步作業等待時間以及時間逾時操作)
a. Page標誌加屬性: Async="true" AsyncTimeout="5" , 添加後代碼如下:
1<%@ Page Language="C#" AutoEventWireup="true" CodeFile="AsyncPageTask.aspx.cs" Inherits="AsyncPageTask" Async="true" AsyncTimeout="5" %>
b. 後台代碼
1public partial class AsyncPageTask : System.Web.UI.Page 2{ 3 private WebRequest _request; 4 5 protected void Page_Load(object sender, EventArgs e) 6 { 7 PageAsyncTask task = new PageAsyncTask( 8 new BeginEventHandler(BeginAsyncOperation), 9 new EndEventHandler(EndAsyncOperation), 10 new EndEventHandler(TimeoutAsyncOperation), 11 null 12 ); 13 14 RegisterAsyncTask(task); 15 } 16 17 IAsyncResult BeginAsyncOperation(object sender, EventArgs e, AsyncCallback cb, object state) 18 { 19 _request = WebRequest.Create("http://blog.csdn.net/chengking"); 20 return _request.BeginGetResponse(cb, state); 21 } 22 23 void EndAsyncOperation(IAsyncResult ar) 24 { 25 string text; 26 using (WebResponse response = _request.EndGetResponse(ar)) 27 { 28 using (StreamReader reader = new StreamReader(response.GetResponseStream())) 29 { 30 text = reader.ReadToEnd(); 31 } 32 } 33 34 lbDisplay.Text = text.ToString(); 35 } 36 37 //時間逾時執行操作 38 void TimeoutAsyncOperation(IAsyncResult ar) 39 { 40 lbDisplay.Text = "Failture!"; 41 } 42} |
(三).遺留問題.
第二種方式: 資料庫物件SqlCommand實現非同步呼叫功能
(對應範例程式碼中的頁面: AsyncVisitDatabase.aspx),範例程式碼我始終沒有調試成功!
資料庫裡有資料,但顯示不到GridView中去.
如哪位能調試通過,敬請指點!!!