top
Loading...
體驗ASP.NET2.0中的異步頁功能
(一).簡單介紹實現原理

下圖左為未使用異步頁功能執行過程(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中去.

如哪位能調試通過,敬請指點!!!
作者:http://www.zhujiangroad.com
來源:http://www.zhujiangroad.com
北斗有巢氏 有巢氏北斗