探索AJAX中的訊息傳輸模式(一)

weixin_34304013發表於2008-06-23
      在我們使用AJAX的應用中,訊息傳輸有那些方式呢?純文字、帶HTML的文字、XML、JSON?還有???在許多情況下,純文字的訊息傳輸就足夠了。例如,要傳輸一個使用者名稱,使用者密碼,或是使用者聯絡方法(PHONE,EMAIL,MSN)等,通常都是以文字的形式傳輸的。又比如複雜點的資料資訊,表格、物件或者是???,這樣我們可以使用XML或是JSON來格式化資料後進行傳輸。
 
      有這樣一個AJAX的應用場合,提供一系列的標籤連線,讓使用者任意選擇,瀏覽器向伺服器傳送請求查詢得到想要的資料資訊。下面就以這個應用討論下訊息傳輸。

一、普通的文字訊息傳輸
      建立一ASP.NET AJAX應用程式,先為AJAXMessageText.aspx頁面做好簡單的佈局準備,我們採用HyperLink控制元件做為導航連線,放置在一個table裡,並設定一單元格作為資料顯示區,設定其作為伺服器控制元件執行(runat="server"),如下圖示:
        
       各個控制元件的命名以資料顯示區的名稱如下:
1 <asp:HyperLink ID="hlAjax" runat="server" Text="AJAX" NavigateUrl="JavaScript:void(0);" />
2 <asp:HyperLink ID="hlAspnet" runat="server" Text="ASP.NET" NavigateUrl="JavaScript:void(0);" />
3<asp:HyperLink ID="hlCastle" runat="server" Text="Castle" NavigateUrl="JavaScript:void(0);" />
4<asp:HyperLink ID="hlService" runat="server" Text="WebService" NavigateUrl="JavaScript:void(0);" />
5<asp:HyperLink ID="hlHtml" runat="server" Text="Html"  NavigateUrl="JavaScript:void(0);"/>
6<td runat="server" colspan="2" rowspan="5" style="background-color: #00ffff; text-align: left"  valign="top" id="resultText">

       使用者通過點選HyperLink控制元件,客戶端向伺服器傳送請求,返回的資料可能來自不同的地方(資料庫,XML,普通的檔案.....),這裡以Message類來封裝這些資料,詳細程式碼定義如下:

Message
 1/**//// <summary>
 2/// Message 的摘要說明
 3/// </summary>

 4public class Message
 5{
 6    public  string AJAX=string.Empty;
 7    public  string ASPNET=string.Empty;
 8    public  string CASTLE=string.Empty;
 9    public  string WEBSERVICE=string.Empty;
10    public string HTML = string.Empty; 
11
12    StringBuilder str = null;
13
14    public Message()
15    {
16        str = new StringBuilder();
17        str.Append("Ajax提供與伺服器非同步通訊的能力,從而使使用者從請求/響應的迴圈中解脫出來。");
18        str.Append("藉助於Ajax,可以在使用者單擊按鈕時,使用JavaScript和DHTML立即更新UI,");
19        str.Append(" 並向伺服器發出非同步請求,以執行更新或查詢資料庫。");
20        AJAX = str.ToString();
21
22
23        str = new StringBuilder();
24        str.Append("Microsoft 的 ASP.NET 和 Visual Studio 組將出席於曼德勒海灣度假舉行的 ASP.NET Connections 會議。");
25        str.Append("請參加深入而前沿的 ASP.NET、Visual Studio & .NET、SQL 和 Mobile Connections 交流會並同與會的");
26        str.Append("Microsoft 和業界專家會晤。即時瞭解 Microsoft 許多令人驚喜的公告。");
27        ASPNET = str.ToString();
28
29        str = new StringBuilder();
30        str.Append("Castle是針對.NET平臺的一個開源專案,從資料訪問框架ORM到IOC容器,再到WEB層的MVC框架、AOP,");
31        str.Append("基本包括了整個開發過程中的所有東西,為我們快速的構建企業級的應用程式提供了很好的服務。");
32        CASTLE = str.ToString();
33
34
35        str = new StringBuilder();
36        str.Append("Web Service 是在 Internet 上進行分散式計算的基本構造塊,是元件物件技術在 Internet 中的延伸,");
37        str.Append("是一種部署在 Web 上的元件。它融合了以元件為基礎的開發模式和 Web 的出色效能。");
38        WEBSERVICE = str.ToString();
39
40        str = new StringBuilder();
41        str.Append("<span style="+"font-weight:bold;font-size:20;color:Red;>");
42        str.Append("帶有HTML的字串,返回此字串,所擁有的樣式等都可以得到解析!");
43        str.Append("</span>");
44        HTML = str.ToString();
45    }

46}

     在ASP.NET AJAX應用中,客戶端和伺服器端進行資料通訊絕大多數都是通過WebService來完成,這裡我們為Message所類的資料方便了與客戶端互動提供一個WebService:
 1[WebService(Namespace = "http://tempuri.org/")]
 2[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
 3[ScriptService]
 4public class MessageWebService : System.Web.Services.WebService {
 5
 6    public MessageWebService () { }
 7
 8    [WebMethod]
 9    public string GetMessage(string text)
10    {
11        Message message = new Message();
12        string str = string.Empty;
13        switch (text)
14        {
15            case "AJAX": str = message.AJAX; break;
16            case "ASPNET": str = message.ASPNET; break;
17            case "CASTLE": str = message.CASTLE; break;
18            case "SERVER": str = message.WEBSERVICE; break;
19            case "HTML": str = message.HTML; break;
20        }

21        return str;
22    }

23}

     方法GetMessage提供根據客戶端傳遞過來的引數返回Message類裡所封裝的相應資料。此時,我們就應該著手客戶端請求的傳送處理,在ASP.NET AJAX應用裡,我們可以很方便的通過ScriptManager引入WebService:

1<asp:ScriptManager ID="ScriptManager1" runat="server">
2   <Services>
3      <asp:ServiceReference Path="MessageWebService.asmx" />
4   </Services>
5</asp:ScriptManager>
   
      在客戶端,通過ASP.NET AJAX對JavaScript的擴充套件,我們可以很方便的得到各個控制元件的引用,以及呼叫WebService方法,設定回撥函式來處理返回值,下面是客戶端JS的完整程式碼:
 1<script type="text/javascript">
 2     var hlAjax;
 3     var hlAspnet;
 4     var hlCastle;
 5     var hlService;
 6     var hlHtml;
 7     var resultText;
 8     
 9     //初始化控制元件引用及事件
10     function pageLoad()
11     {
12        hlAjax = $get("<% =hlAjax.ClientID %>");
13        hlAspnet = $get("<% =hlAspnet.ClientID %>");
14        hlCastle = $get("<% =hlCastle.ClientID %>");
15        hlService = $get("<% =hlService.ClientID %>")
16        hlHtml = $get("<% = hlHtml.ClientID %>");
17        
18        $addHandler(hlAjax,"click",onClick);
19        $addHandler(hlAspnet,"click",onClick);
20        $addHandler(hlCastle,"click",onClick);
21        $addHandler(hlService,"click",onClick);
22        $addHandler(hlHtml,"click",onClick);
23        
24        resultText = $get("<% = resultText.ClientID %>");
25     }

26     
27     function onClick(eventElement)
28     {
29        var topic = false;
30        switch(eventElement.target.id)
31        {
32           case hlAjax.id:topic = "AJAX";break;
33           case hlAspnet.id:topic = "ASPNET";break;
34           case hlCastle.id:topic = "CASTLE";break;
35           case hlService.id:topic = "SERVER";break;
36           case hlHtml.id:topic = "HTML";break;
37           
38        }

39        //引用WebService獲取資料
40        MessageWebService.GetMessage(topic,onGetTextMessageCallback);
41     }

42     
43     //回撥函式
44     function onGetTextMessageCallback(text)
45     {
46        resultText.innerHTML=text;
47     }

48     </script>

      上述中,通過AJAX所提供的$get()方法獲取到各控制元件的客戶端引用,並通過$addHandler()方法為其新增了客戶端事件,注意有個HTML的連線,這裡我們追逐到Message類裡:
1str = new StringBuilder();
2str.Append("<span style="+"font-weight:bold;font-size:20;color:Red;>");
3str.Append("帶有HTML的字串,返回此字串,所擁有的樣式等都可以得到解析!");
4str.Append("</span>");
5HTML = str.ToString();
      類裡所封裝的html對應的字元傳是帶有css樣式及html標識的字串,返回這個html字串那客戶端是否能得到解析??答案是肯定的,這裡只是做到了使用者點選相應的連線就傳送請求到伺服器,要使這個應用完善,我們還得為這個應用初始化一個顯示值:
1public partial class AjaxMessageText : System.Web.UI.Page
2{
3    protected void Page_Load(object sender, EventArgs e)
4    {
5        this.resultText.InnerHtml = new Message().AJAX;
6    }

7}

看看下面的執行結果:
     
 
二、複雜型別的訊息傳輸
      我們模擬一個資料庫查詢功能,根據客戶端的請求條件查詢資料庫,把查詢到的資料返回到客戶端顯示。這樣一個應用一般來說可以通過XML來傳輸。ASPX頁面設計如下:

      正如上圖所示,以MSSQL2000裡的Northwind資料庫裡的Employees表為例,根據客戶端的條件(排序欄位,提取的記錄條數)查詢資料庫,下面是資料庫訪問程式碼:
資料庫訪問程式碼
 1public class DataAccess
 2{
 3    private static string strCon = "Data Source=.;database=northwind;uid=sa;pwd=;";
 4    public DataAccess()
 5    {
 6    }

 7
 8    public static DataTable GetEmployees(string orderBy, int maxRows)
 9    {
10        string cmdText = "select top " + maxRows;
11        cmdText += " EmployeeID,LastName,City,Country ";
12        cmdText += "from Employees order by " + orderBy;
13        return Exce(cmdText);
14    }

15
16    private static DataTable Exce(string cmdText)
17    {
18        SqlConnection conn = new SqlConnection(strCon);
19        SqlDataAdapter sda = new SqlDataAdapter(cmdText, conn);
20        DataSet ds = new DataSet();
21        sda.Fill(ds);
22        return ds.Tables[0];
23    }

24}

     資料庫訪問方法GetEmployees提供根據客戶傳遞的引數查詢Employees表裡的資料並以DataTable的形式返回,到這裡我們同上面一樣可以藉助WebService來處理返回的DataTable,將資料處理為一個XML字串返回到客戶端:
 1[WebMethod]
 2public string GetEmployees(string orderBy, int manxRows)
 3{
 4    DataTable dt = DataAccess.GetEmployees(orderBy, manxRows);
 5    StringBuilder xml = new StringBuilder();
 6    xml.Append("<?xml version='1.0' ?>");
 7    xml.Append("<Employees>");
 8
 9    foreach (DataRow row in dt.Rows)
10    {
11        string id = row["EmployeeID"].ToString();
12        string name = row["LastName"].ToString();
13        string city = row["City"].ToString();
14        string country = row["Country"].ToString();
15        xml.Append("<Employee>");
16        xml.Append("<EmployeeID>" + id + "</EmployeeID>");
17        xml.Append("<LastName>" + name + "</LastName>");
18        xml.Append("<City>" + city + "</City>");
19        xml.Append("<Country>" + country + "</Country>");
20        xml.Append("</Employee>");
21    }

22    xml.Append("</Employees>");
23    return xml.ToString();
24}

     在客戶端的處理程式上,大致和上面的普通的文字訊息差不多,其實整個AJAX應用基本上都是應用的一個模式,從傳送請求--->響應請求--->資料傳輸--->處理回撥。客戶端工作量最大的就是在回撥函式裡,下面是本示例的回撥函式定義:

 1//回撥函式
 2function onXmlMessageCallback(result)
 3{
 4   var xml;
 5   if(window.ActiveXObject)  //IE
 6   {
 7       xml = new ActiveXObject("Microsoft.XMLDOM");
 8       xml.async = false;
 9       xml.loadXML(result);
10   }

11   else
12   {
13       var parser = new DOMParser();
14       xml = parser.parseFromString(result,"text/xml");
15   }

16   
17   var employees = xml.getElementsByTagName("Employee");
18   var html = new Sys.StringBuilder();
19   html.append("<table width='500px' cellspacing='1' cellpadding='0' border='0' bgcolor='#999999'>");
20   //構建表頭
21   html.append("<tr>");
22   if(cbID.checked)
23      html.append("<td bgcolor='lightblue'><b>ID</b></td>");
24   if(cbLastName.checked)
25      html.append("<td bgcolor='lightblue'><b>LastName</b></td>"); 
26   if(cbCity.checked)
27      html.append("<td bgcolor='lightblue'><b>City</b></td>"); 
28   if(cbCountry.checked)
29      html.append("<td bgcolor='lightblue'><b>Country</b></td>");
30   html.append("<tr>");
31   
32   //構建資料行
33   for (var i=0; i<employees.length;i++)
34   {
35       html.append("<tr>");
36       if(cbID.checked)
37       {
38           var id= employees[i].getElementsByTagName("EmployeeID")[0].childNodes[0].nodeValue;
39           html.append("<td>"+id+"</td>");
40       }

41       if(cbLastName.checked)
42       {
43           var LastName= employees[i].getElementsByTagName("LastName")[0].childNodes[0].nodeValue;
44           html.append("<td>"+LastName+"</td>");
45       }

46       if(cbCity.checked)
47       {
48           var City= employees[i].getElementsByTagName("City")[0].childNodes[0].nodeValue;
49           html.append("<td>"+City+"</td>");
50       }

51       if(cbCountry.checked)
52       {
53           var Country= employees[i].getElementsByTagName("Country")[0].childNodes[0].nodeValue;
54           html.append("<td>"+Country+"</td>");
55       }

56       html.append("</tr>");
57   }

58   
59   html.append("</table>");
60   resultXml.innerHTML=html.toString();
61}

    在客戶端的回撥函式裡,把伺服器端返回的字串解析為一個xml物件,通過JavaScript操作DOM將xml物件裡的每一條資料解析後存入陣列,隨後根據頁面上選擇要顯示欄位動態構造html程式碼並顯示在指定的位置(resutlXml)。 下面是客戶端的完整程式碼:
客戶端的完整程式碼
  1<%@ Page Language="C#" AutoEventWireup="true" CodeFile="AjaxMessageXML.aspx.cs" Inherits="AjaxMessageXML" %>
  2
  3<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  4
  5<html xmlns="http://www.w3.org/1999/xhtml" >
  6<head runat="server">
  7    <title>無標題頁</title>
  8</head>
  9<body>
 10    <form id="form1" runat="server">
 11    <asp:ScriptManager ID="ScriptManager1" runat="server">
 12      <Services>
 13         <asp:ServiceReference Path="MessageWebService.asmx" />
 14      </Services>
 15    </asp:ScriptManager>
 16        以MSSQL 2000裡的示例資料庫Northwind裡的Employees表為例<br />
 17        所要顯示的列 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
 18        &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
 19        方式欄位 &nbsp; &nbsp;&nbsp; 提取記錄行數<br />
 20        <asp:CheckBox ID="cbID" runat="server" Text="ID" />
 21        &nbsp;
 22        <asp:CheckBox ID="cbLastName" runat="server" Text="LastName" />
 23        &nbsp;
 24        <asp:CheckBox ID="cbCity" runat="server" Text="City" />
 25        &nbsp; &nbsp;
 26        <asp:CheckBox ID="cbCountry" runat="server" Text="Country" />
 27        &nbsp;
 28        <asp:DropDownList ID="ddlOrder" runat="server">
 29            <asp:ListItem Value="EmployeeID" Text="ID"></asp:ListItem>
 30            <asp:ListItem Value="LastName" Text="LastName"></asp:ListItem>
 31            <asp:ListItem Value="City" Text="City"></asp:ListItem>
 32            <asp:ListItem Value="Country" Text="Country"></asp:ListItem>
 33        </asp:DropDownList>
 34        &nbsp; &nbsp; &nbsp;<asp:DropDownList ID="ddlRows" runat="server">
 35            <asp:ListItem>1</asp:ListItem>
 36            <asp:ListItem>2</asp:ListItem>
 37            <asp:ListItem>3</asp:ListItem>
 38            <asp:ListItem>5</asp:ListItem>
 39            <asp:ListItem>8</asp:ListItem>
 40            <asp:ListItem>10</asp:ListItem>
 41        </asp:DropDownList>
 42        &nbsp;&nbsp;
 43        <input id="buttonGO" style="width: 53px" type="button" value="GO" />
 44        <hr />
 45        <div id="resultXml"></div>
 46        
 47        <script type="text/javascript">
 48        var cbID;
 49        var cbLastName;
 50        var cbCity;
 51        var cbCountry;
 52        var ddlOrder;
 53        var ddlRows;
 54        var resultXml;
 55        var buttonGO;
 56        
 57        //初始化控制元件引用及事件
 58        function pageLoad()
 59        {
 60           cbID = $get("<% =cbID.ClientID %>");
 61           cbLastName = $get("<% =cbLastName.ClientID %>");
 62           cbCity = $get("<% =cbCity.ClientID %>");
 63           cbCountry = $get("<% =cbCountry.ClientID %>");
 64           
 65           ddlOrder = $get("<% =ddlOrder.ClientID %>");
 66           ddlRows = $get("<% =ddlRows.ClientID %>");
 67           
 68           resultXml = $get("resultXml");
 69           buttonGO = $get("buttonGO");
 70           $addHandler(buttonGO,"click",onButtonClicked);
 71           
 72           onButtonClicked(null);
 73        }

 74        
 75        function onButtonClicked(eventElement)
 76        {
 77           if(!cbID.checked && !cbLastName.checked && cbCity.checked && cbCountry.checked)
 78           {
 79               alert("至少選擇一列!");
 80               return;
 81           }

 82           
 83           var orderBy = ddlOrder.options[ddlOrder.selectedIndex].value;
 84           var maxRows = ddlRows.options[ddlRows.selectedIndex].value;
 85           
 86           //呼叫WebService獲取資料
 87           MessageWebService.GetEmployees(orderBy,maxRows,onXmlMessageCallback);
 88        }

 89        
 90        //回撥函式
 91        function onXmlMessageCallback(result)
 92        {
 93           var xml;
 94           if(window.ActiveXObject)  //IE
 95           {
 96               xml = new ActiveXObject("Microsoft.XMLDOM");
 97               xml.async = false;
 98               xml.loadXML(result);
 99           }

100           else
101           {
102               var parser = new DOMParser();
103               xml = parser.parseFromString(result,"text/xml");
104           }

105           
106           var employees = xml.getElementsByTagName("Employee");
107           var html = new Sys.StringBuilder();
108           html.append("<table width='500px' cellspacing='1' cellpadding='0' border='0' bgcolor='#999999'>");
109           //構建表頭
110           html.append("<tr>");
111           if(cbID.checked)
112              html.append("<td bgcolor='lightblue'><b>ID</b></td>");
113           if(cbLastName.checked)
114              html.append("<td bgcolor='lightblue'><b>LastName</b></td>"); 
115           if(cbCity.checked)
116              html.append("<td bgcolor='lightblue'><b>City</b></td>"); 
117           if(cbCountry.checked)
118              html.append("<td bgcolor='lightblue'><b>Country</b></td>");
119           html.append("<tr>");
120           
121           //構建資料行
122           for (var i=0; i<employees.length;i++)
123           {
124               html.append("<tr>");
125               if(cbID.checked)
126               {
127                   var id= employees[i].getElementsByTagName("EmployeeID")[0].childNodes[0].nodeValue;
128                   html.append("<td>"+id+"</td>");
129               }

130               if(cbLastName.checked)
131               {
132                   var LastName= employees[i].getElementsByTagName("LastName")[0].childNodes[0].nodeValue;
133                   html.append("<td>"+LastName+"</td>");
134               }

135               if(cbCity.checked)
136               {
137                   var City= employees[i].getElementsByTagName("City")[0].childNodes[0].nodeValue;
138                   html.append("<td>"+City+"</td>");
139               }

140               if(cbCountry.checked)
141               {
142                   var Country= employees[i].getElementsByTagName("Country")[0].childNodes[0].nodeValue;
143                   html.append("<td>"+Country+"</td>");
144               }

145               html.append("</tr>");
146           }

147           
148           html.append("</table>");
149           resultXml.innerHTML=html.toString();
150        }

151        
</script>
152    </form>
153</body>
154</html>
155

      文章中有部分內容我作了修改,在原文中加入了示例分析。希這篇文章對大家有所幫助,要更深入的學習AJAX是資料傳輸請查閱其他相關書籍或資料。歡迎大家拍磚指正,謝謝。
-------------------------------------------------------------------------------------------------------------
參考資源:www.dofactory.com
相關文章:探索AJAX中的訊息傳輸模式(二)

相關文章