现在的位置: 首页 > 综合 > 正文

如何返回一个 DataTable 到客户端 JavaScript

2014年10月06日 ⁄ 综合 ⁄ 共 3992字 ⁄ 字号 评论关闭

如何返回一个 DataTable 到客户端 JavaScript

当在 WebService 中直接返回 DataTable 时,会出现循环引用的异常,

何为循环引用?循环引用就是在引用上,

A 引用了 B,而 B 又引用了 A,这就是一个典型的循环引用,

当有循环引用时,在进行 JSON 序列化时会报出出现循环引用的异常,

例如

我在 WebService 中返回的是一个 DataTable 类型,

DataTable 算是一个极其复杂的对象类型了,

这个类型在进行 JSON 序列化时,便会产生一个循环引用,

在序列化其中的 System.Reflection.Module 对象时会发生循环引用,

从而会导致 JSON 序列化失败,导致整个的异步调用 WebService 失败,

看一下这个失败的例子吧,

首先看 .asmx

[WebMethod]

[System.Web.Script.Services.ScriptMethod]
public DataTable GetDataTable()
{
DataTable myTable = new DataTable();

DataRow myRow;
myTable.Columns.Add("ID", typeof(string));
myTable.Columns.Add("Name", typeof(string));
myTable.Columns.Add("Sex", typeof(string));
myTable.Columns.Add("FatherName", typeof(string));
myTable.Columns.Add("Address", typeof(string));

string conStr = WebConfigurationManager.

ConnectionStrings["Demo"].ConnectionString;
string sqlStr = "SELECT 身份证号码,学生姓名,性别,家长姓名,家庭地址 FROM 学生";

using (SqlConnection sqlCon = new SqlConnection(conStr))

{
sqlCon.Open();
using (SqlCommand sqlCom = sqlCon.CreateCommand())
{
sqlCom.CommandText = sqlStr;
using (SqlDataReader sqlDr = sqlCom.ExecuteReader())
{
while (sqlDr.Read())
{
myRow = myTable.NewRow();
myRow["ID"] = sqlDr.GetSqlString(0).Value;
myRow["Name"] = sqlDr.GetSqlString(1).Value;
myRow["Sex"] = sqlDr.GetBoolean(2).ToString();
myRow["FatherName"] = sqlDr.GetSqlString(3).Value;
myRow["Address"] = sqlDr.GetSqlString(4).Value;
myTable.Rows.Add(myRow);

}
}
}
}
return myTable;
}

显而易见,上面这个 WebService 返回的是一个 DataTable 对象

再看一下客户端 JavaScript 代码

function PageLoad() {
深入浅出_ASP.NET_AJAX.Demo__10__Use.
set_timeout(2000);
深入浅出_ASP.NET_AJAX.Demo__10__Use.
set_defaultFailedCallback(OnFailedCallback);
深入浅出_ASP.NET_AJAX.Demo__10__Use.
set_defaultSucceededCallback(OnSucceededCallback);
}

function GetDataTable_onclick() {

深入浅出_ASP.NET_AJAX.Demo__10__Use.GetDataTable();

}

function OnFailedCallback(error, userContext, methodName) {

var msg = "";
if (methodName == "GetDataTable") {
msg += "\nGetDataTable 在异步执行期间发生下列错误";
}

msg += "\n 异常信息: " + error.get_message();

msg += "\n 异常类型: " + error.get_exceptionType();
msg += "\n 状态码 : " + error.get_statusCode();
msg += "\n 堆栈信息: " + error.get_stackTrace();

alert(msg);
}

function OnSucceededCallback(result, userContext, methodName) {

}
执行中由于 DataTable 在序列化时会发生循环引用,所以很明显,会失败

image

单击这个 Button 后的结果为

image

以上是在从 WebService 中直接返回 DataTable 时出现的异常,

那么该如何解决这个问题呢,使得能够从服务端顺利的返回 DataTable 中的数据呢?

事实上,应该明确以下几点,

在服务端与客户端进行传递数据的格式是 JSON (JavaScript Object Notation),

这个格式简单轻便,

最常用的以一般的字符串类型,
List<T> 集合类型以及

字典Dictionary<string ,T>类型进行数据的传递和转换

其中较为特殊的是 Dictionary<string ,T>,

其中的第一个类型必须是 string ,否则在客户端将无法识别,

而 DataTable 或者 DataSet 这些复杂数据类型已经远远超出了上面的三种类型的范围,

所以无法进行正常的 JSON 序列化,

那么如何才能正常的把 DataTable 中的数据正确传递给 JavaScript 呢?

其中有两种方法对这种情况可以解决,

第一种是使用 JavaScriptConverter 来实现,

第二种则是自定义数据类型,

把 DataTable 这些复杂数据类型先转换为上面的三种数据类型再传递。

本次主要讲解一下的是第二种方法,

第一种方法相对来说更为复杂,您必须定义自己的 Converter 来实现,

同时将这个 Converter 在 Web.Config 中实现注册,

并且必须自行控制解除或者设置循环引用,相对来说比较繁琐,

但是第二种方式则比较简单,

因为我是采用在服务端将 DataTable 先转化为自定义数据类型,

然后再返回我的自定义数据类型,从而间接的实现了返回 DataTable ,

而第一种使用 JavaScriptConverter 则是直接返回的 DataTable 。

改进如下(使得上个失败的例子可以成功返回 DataTable 中的数据)

通过添加一个类来实现将 DataTable 转换为 List<T> 或者 Dictionary<string ,T>来返回,

类的代码如下

public class Demo__10__Use__Converter

{
private DataTable myTable;

//在构造函数中传入一个 DataTable

public Demo__10__Use__Converter(DataTable myTable)

{
this.myTable = myTable;
}

//注意返回的类型,将 DataTable 转换后返回的类型是 List<T>

//此处定义了多级的 List
//第一级 List 来储存 DataTable 中的每一行,也就是储存第二级 List
//而第二级 List 则是用来储存 DataTable 中每一行中的数据,即 Dictionary
//而 Dictionary 则是用来储存每一个单元格的数值
public List<List<Dictionary<string, string>>> Converter()

{
//第一级 List
List<List<Dictionary<string, string>>> firstList =

new List<List<Dictionary<string, string>>>();

//遍历 DataTable 的每一行
for (int i = 0; i < this.myTable.Rows.Count; i++)
{
//第二级 List
List<Dictionary<string, string>> secondList =

new List<Dictionary<string, string>>();

//遍历 DataTable 的每一列
for (int j = 0; j < this.myTable.Columns.Count; j++)
{
//获取这个单元格所在列的列名
string columnName = this.myTable.Columns[j].ColumnName;
Dictionary<string, string> myDictionary =
new Dictionary<string, string>();

//将这个单元格的数值存储在字典中
myDictionary[columnName] = this.myTable.Rows[i][j].ToString();
secondList.Add(myDictionary);
}
firstList.Add(secondList);
}
return firstList;
}
}

然后再在 WebService 中更改一点点就 OK 了

image

接下来就是要在 JavaScript 中解析,

传递过来的 List<List<Dictionary<string,string>>>类型并且输出了

image

再看一下结果吧

image

该部分的代码需要仔细斟酌,慢慢理解

以上就是在服务端传递 DataTable 到客户端 JavaScript 的整个范例,

大家可以慢慢研究。

抱歉!评论已关闭.