3.7.6 DataTable和DataSet
DataTable和DataSet是ADO.NET中的重要概念,這兩個對象均非常復雜,其中包含了大量的復雜類型和循環(huán)引用。為了能夠在ASP.NET AJAX異步通訊層中傳遞這兩種類型的數(shù)據(jù),微軟公司在ASP.NET AJAX Futures CTP版本中給出了自定義的DataTable和DataSet轉(zhuǎn)換方案——即借助于ASP.NET AJAX強大的可擴展性,通過自定義JavaScriptConverter實現(xiàn)DataTable和DataSet類型的客戶端/服務器端自動轉(zhuǎn)換。
參考:在某些情況下,我們也需要通過編寫自定義的JavaScriptConverter來為實際項目中遇到的某些復雜類型給出自定義的轉(zhuǎn)換方案。關(guān)于JavaScriptConverter組件的基本知識,請參考第2章;關(guān)于自定義JavaScriptConverter的編寫方法,將在第III卷中介紹。
若想在ASP.NET AJAX異步通訊層中傳遞DataTable和DataSet這兩種類型的數(shù)據(jù),首先我們應該確保安裝了ASP.NET AJAX的Futures CTP部分(關(guān)于對ASP.NET AJAX的Futures CTP部分的介紹以及安裝方法,請參考第I卷),并在Web站點中添加了對Microsoft.Web.Preview.dll程序集的引用(將該程序集拷貝到Web站點的\bin文件夾下),如圖3-31所示。

圖3-31在Web站點中添加對Microsoft.Web.Preview.dll程序集的引用
隨后讓我們在web.config文件中啟用ASP.NET AJAX Futures CTP中自帶的DataTable和DataSet相關(guān)JavaScriptConverter組件。將如下代碼添加至<configuration />\<system.web.extensions />\<scripting />\<webServices />節(jié)中:
<jsonSerialization>
<converters>
<add name="DataSetConverter" type="Microsoft.Web.Preview.Script.Serialization.Converters.DataSetConverter, Microsoft.Web.Preview, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<add name="DataRowConverter" type="Microsoft.Web.Preview.Script.Serialization.Converters.DataRowConverter, Microsoft.Web.Preview, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<add name="DataTableConverter" type="Microsoft.Web.Preview.Script.Serialization.Converters.DataTableConverter, Microsoft.Web.Preview, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
</converters>
</jsonSerialization>
進行上述配置之后,我們即可ASP.NET AJAX異步通訊層中傳遞DataTable和DataSet了,讓我們通過一個實例程序說明具體的使用方法。
在本示例程序,我們將通過ASP.NET AJAX異步通訊層從服務器端Web Service方法中取得一個DataTable,并將其中的數(shù)據(jù)顯示為頁面中的一個HTML <table />。首先從Web Service開始,代碼如下,注意不要忘記為該Web Service類添加[System.Web.Script.Services.ScriptService]屬性:
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.Web.Script.Services.ScriptService]
public class DataService : System.Web.Services.WebService
{
[WebMethod]
public DataTable GetDataTable(string tableName)
{
// 設定DataTable的名稱
DataTable table = new DataTable(tableName);
// 為該DataTable添加兩列
table.Columns.Add(new DataColumn("Id", typeof(int)));
table.Columns.Add(new DataColumn("Name", typeof(string)));
// 添加5行
for (int i = 0; i < 5; ++i)
{
DataRow newRow = table.NewRow();
newRow["Id"] = i;
newRow["Name"] = string.Format("name {0}", i);
table.Rows.Add(newRow);
}
return table;
}
}
然后再客戶端ASP.NET頁面中添加ScriptManager控件,并引入該Web Service:
<asp:ScriptManager ID="sm" runat="server">
<Services>
<asp:ServiceReference Path="Services/DataService.asmx" />
</Services>
</asp:ScriptManager>
來到頁面的UI部分:添加一個用來出發(fā)對服務器端Web Service方法的異步調(diào)用的按鈕和一個用來顯示由服務器端返回值構(gòu)造出的HTML <table />的<div />:
<input id="btnGetDataTable" type="button" value="Get DataTable"
onclick="return btnGetDataTable_onclick()" />
<div id="result">
</div>
btnGetDataTable按鈕的click事件的處理函數(shù)定義如下:
function btnGetDataTable_onclick() {
DataService.GetDataTable("My Table", onSucceeded);
}
此時,如果一切順利的話,在回調(diào)函數(shù)onSucceeded()中我們已經(jīng)可以看到服務器端返回的DataTable的基本結(jié)構(gòu)了。比如下面的代碼就使用Sys.Debug.traceDump()方法(關(guān)于Sys.Debug.traceDump()方法,請參考第1章中的介紹)查看了result對象的詳細結(jié)構(gòu):
function onSucceeded(result) {
Sys.Debug.traceDump(result);
}
在Visual Studio的“Output”窗口中,我們即可看到該客戶端DataTable的完整結(jié)構(gòu)以及其中所包含的數(shù)據(jù),如圖3-32所示。

圖3-32 客戶端DataTable的完整結(jié)構(gòu)以及其中所包含的數(shù)據(jù)
當然,在Visual Studio的調(diào)試器中,我們也可以直接查看該DataTable的結(jié)構(gòu)和數(shù)據(jù),如圖3-33所示。

圖3-33 服務器端DataTable類型在客戶端的結(jié)構(gòu)
從圖3-32和圖3-33可以看到,ASP.NET AJAX異步通訊層為服務器端DataTable生成的客戶端JavaScript相應類型還是比較簡單的,很多原始DataTable中的數(shù)據(jù)之間的關(guān)系和約束均沒有保留下來。不過在一般的開發(fā)場景中,這些信息已經(jīng)足夠滿足我們的使用需求了——畢竟,DataTable中的所有“數(shù)據(jù)”都絲毫不差地保留了下來。
參考:ASP.NET AJAX在Futures CTP版本中提供了更為完備的客戶端DataTable類型,其完全限定名為Sys.Preview.Data.DataTable。有關(guān)該類型的詳細介紹,請參考本書8.2.2節(jié)。
接下來讓我們回到該示例程序的編寫中來,完成回調(diào)函數(shù)onSucceeded(),將該客戶端DataTable中的數(shù)據(jù)以HTML <table />的形式顯示出來。完成后的回調(diào)函數(shù)onSucceeded()代碼如下,其中代碼流程均有詳細注釋,這里不贅:
function onSucceeded(result) {
// 測試
//Sys.Debug.traceDump(result);
//debugger;
// 得到兩列的名稱
var idColName = result.columns[0].name;
var nameColName = result.columns[1].name;
// 得到DataTable中的行集合
var rows = result.rows;
// 創(chuàng)建表格頭
var builder = new Sys.StringBuilder("<table border=1>");
builder.append(
String.format(
"<tr><td>{0}</td><td>{1}</td></tr>",
idColName,
nameColName
)
);
// 創(chuàng)建表格內(nèi)容
for (var rowIndex = 0; rowIndex < rows.length; ++ rowIndex) {
builder.append(
String.format(
"<tr><td>{0}</td><td>{1}</td></tr>",
rows[rowIndex][idColName],
rows[rowIndex][nameColName]
)
);
}
builder.append("</table>");
// 顯示表格
$get("result").innerHTML = builder.toString();
}
至此,我們已經(jīng)完成了本示例程序的編寫。運行該程序并點擊“Get DataTable”按鈕,將看到如圖3-34所示的界面。

圖3-34 從服務器端取得DataTable對象并顯示在頁面中
若是想得到DataSet對象,那么ASP.NET AJAX異步通訊層也有著不錯的支持。在上面的DataService Web Service類中再添加如下一個方法:
[WebMethod]
public DataSet GetDataSet(string[] tableNames)
{
DataSet dataSet = new DataSet();
// 根據(jù)傳入的DataTable名稱創(chuàng)建各個DataTable
for (int i = 0; i < tableNames.Length; ++i)
{
dataSet.Tables.Add(GetDataTable(tableNames[i]));
}
return dataSet;
}
該方法接受一個字符串數(shù)組,并根據(jù)該數(shù)組的長度創(chuàng)建相應個數(shù)的DataTable,然后將這些DataTable打包到一個DataSet中返回給客戶端。
在客戶端,我們可以使用如下JavaScript調(diào)用該Web Service方法:
var dataTableNames = ["My Table 1", "My Table 2", "My Table 3"];
DataService.GetDataSet(dataTableNames, onSucceeded);
在onSucceeded()回調(diào)函數(shù)中,返回的客戶端DataSet在Visual Studio調(diào)試器中顯示出的結(jié)構(gòu)如圖3-35所示,可以看到該DataSet包含了3個DataTable對象。

圖3-35服務器端DataSet類型在客戶端的結(jié)構(gòu)
雖然這個客戶端版本的DataSet仍舊比較簡單,但一般來講,這樣的數(shù)據(jù)結(jié)構(gòu)已經(jīng)足夠我們使用了。
This posting is provided "AS IS" with no warranties, and confers no rights.