DataTable循环引用错误?——Ajax系列之五(上)
2016-05-23 00:00
369 查看
何谓循环引用?
举个例子来说吧,一个男孩类Boy中可以访问他的女朋友是类Girl,同样,类Girl也可以访问她的男朋友Boy类。而且一个男朋友和女朋友具有对应的关系(一对一);还有一种情况就是一对多的情况,比如Parent可以有多个Child,但是每个Child只可以有一个Parent。
不管是一对多,关联的两个类之间肯定存在一定的对应关系,这种关系就是循环引用。
Ajax中为什么会出现循环引用的错误?
在默认情况下Ajax的服务端和客户端之间传递的都是Json字串,json字串是json对象的字串表现形式,json对象是使用字典和列表(dictionary和list)两种结构互相嵌套、引用的方法来表示的对象;
对于每一个对象来说,我们都可以想象成是一个字典,由key和value组成,一个key个value组成一个item;一个json对象可以有多个item。这样在客户端和服务端传输的Json字串的key和value就发生了循环指向,造成无法解析的错误。
解决办法?
针对常用的DataSet、DataTable和DataRow数据类型,微软已经封装了解决循环引用的类,我们在程序中直接添加引用即可;
针对自定义的复杂类型的数据,我们可以自定义JavascriptConverter来解决循环问题。
核心的思路原理:
破解循环引用的核心思想是:在访问对方类之前,打破原有的引用关系,重新来指定对方类的引用。
=======================================================================================
接下来进入代码实现部分:
![](http://static.oschina.net/uploads/img/201605/23151613_Rdrz.gif)
默认情况下,如果在Ajax中返回一个DataTable,那么会弹出上图的错误提示。
解决方法是:
首先,在程序的Bin目录下添加Microsoft.Web.Preview.dll对象的引用
![](http://static.oschina.net/uploads/img/201605/23151613_7RQs.gif)
然后,在配置文件的system.web.extensions节点->scripting->webServices->jsonSerialization->converters节点中添加序列化类的路径。
在服务端定义GetDataTable方法,创建一个10行2列的DataTable:
客户端使用javascript脚本,调用服务端方法获得表格,并为表格赋值:
客户端调用显示的事件:
运行效果图:
![](http://static.oschina.net/uploads/img/201605/23151613_zvzz.gif)
技术学习:
在客户端使用了Sys.StringBuilder的方法拼接字符串,保证在不同的浏览器下都可以正确的拼接;
使用append方法添加dom元素,sb.append("</table>");
在循环中使用String.format函数,为行赋值,String.format( "<tr><td>{0}</td><td>{1}</td></tr>", result.rows[i]"ID"], result.rows[i].Text));
服务端使用dt.Columns.Add(new DataColumn("ID", typeof(int)));方法添加列字段。
如何解决自定义复杂数据类型的循环引用?
见下篇博客的分析……
举个例子来说吧,一个男孩类Boy中可以访问他的女朋友是类Girl,同样,类Girl也可以访问她的男朋友Boy类。而且一个男朋友和女朋友具有对应的关系(一对一);还有一种情况就是一对多的情况,比如Parent可以有多个Child,但是每个Child只可以有一个Parent。
不管是一对多,关联的两个类之间肯定存在一定的对应关系,这种关系就是循环引用。
Ajax中为什么会出现循环引用的错误?
在默认情况下Ajax的服务端和客户端之间传递的都是Json字串,json字串是json对象的字串表现形式,json对象是使用字典和列表(dictionary和list)两种结构互相嵌套、引用的方法来表示的对象;
对于每一个对象来说,我们都可以想象成是一个字典,由key和value组成,一个key个value组成一个item;一个json对象可以有多个item。这样在客户端和服务端传输的Json字串的key和value就发生了循环指向,造成无法解析的错误。
解决办法?
针对常用的DataSet、DataTable和DataRow数据类型,微软已经封装了解决循环引用的类,我们在程序中直接添加引用即可;
针对自定义的复杂类型的数据,我们可以自定义JavascriptConverter来解决循环问题。
核心的思路原理:
破解循环引用的核心思想是:在访问对方类之前,打破原有的引用关系,重新来指定对方类的引用。
=======================================================================================
接下来进入代码实现部分:
![](http://static.oschina.net/uploads/img/201605/23151613_Rdrz.gif)
默认情况下,如果在Ajax中返回一个DataTable,那么会弹出上图的错误提示。
解决方法是:
首先,在程序的Bin目录下添加Microsoft.Web.Preview.dll对象的引用
![](http://static.oschina.net/uploads/img/201605/23151613_7RQs.gif)
然后,在配置文件的system.web.extensions节点->scripting->webServices->jsonSerialization->converters节点中添加序列化类的路径。
<system.web.extensions> <scripting> <webServices> <!-- Uncomment this line to customize maxJsonLength and add a custom converter --> <jsonSerialization> <!--定义了一些转换dataset、DataRow和datetable的类型--> <converters> <add name="DataSetConverter" type="Microsoft.Web.Preview.Script.Serialization.Converters.DataSetConverter, Microsoft.Web.Preview"/> <add name="DataRowConverter" type="Microsoft.Web.Preview.Script.Serialization.Converters.DataRowConverter, Microsoft.Web.Preview"/> <add name="DataTableConverter" type="Microsoft.Web.Preview.Script.Serialization.Converters.DataTableConverter, Microsoft.Web.Preview"/> <!--注册定义的序列化,type的值是这个类的完整命名,App_Code会自动生成一个应用程序集--> <add name="BoyConverter" type="Converter.BoyConverter, App_Code"/> </converters> </jsonSerialization> </webServices> <!-- <scriptResourceHandler enableCompression="true" enableCaching="true" /> --> </scripting> </system.web.extensions>
在服务端定义GetDataTable方法,创建一个10行2列的DataTable:
<%@ WebService Language="C#" Class="DataTableService" %> using System; using System.Web; using System.Web.Services; using System.Web.Services.Protocols; using System.Web.Script.Services; using System.Data; [WebService(Namespace = "http://tempuri.org/")] [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] [ScriptService] public class DataTableService : System.Web.Services.WebService { [WebMethod] public DataTable GetDataTable() { DataTable dt = new DataTable(); dt.Columns.Add(new DataColumn("ID", typeof(int))); dt.Columns.Add(new DataColumn("Text", typeof(string))); //使用时间作为随机化的种子 Random random = new Random(DateTime.Now.Millisecond); for (int i = 0; i < 10; i++) { dt.Rows.Add(i, random.Next().ToString()); } return dt; } }
客户端使用javascript脚本,调用服务端方法获得表格,并为表格赋值:
<script language="javascript" type="text/javascript"> function getDataTable() { DataTableService.GetDataTable(onSucceeded, onFailed); } function onSucceeded(result) { // alert(result); //提倡使用StringBuilder拼接字符串,保证在不同的浏览器下都可以正确的拼接 var sb = new Sys.StringBuilder("<table border='1'>"); sb.append("<tr><td>ID</td><td>Text</td></tr>"); for (var i = 0; i < result.rows.length; i++) { sb.append( String.format( "<tr><td>{0}</td><td>{1}</td></tr>", result.rows[i]["ID"], result.rows[i].Text)); } sb.append("</table>"); $get("result").innerHTML = sb.toString(); } function onFailed(error) { alert(error.get_message()); } </script>
客户端调用显示的事件:
<asp:ScriptManager ID="ScriptManager1" runat="server"> <Services> <asp:ServiceReference Path="DataTableService.asmx" InlineScript="true" /> </Services> </asp:ScriptManager> <input type="button" value="Get DataTable" onclick="getDataTable();" />
运行效果图:
![](http://static.oschina.net/uploads/img/201605/23151613_zvzz.gif)
技术学习:
在客户端使用了Sys.StringBuilder的方法拼接字符串,保证在不同的浏览器下都可以正确的拼接;
使用append方法添加dom元素,sb.append("</table>");
在循环中使用String.format函数,为行赋值,String.format( "<tr><td>{0}</td><td>{1}</td></tr>", result.rows[i]"ID"], result.rows[i].Text));
服务端使用dt.Columns.Add(new DataColumn("ID", typeof(int)));方法添加列字段。
如何解决自定义复杂数据类型的循环引用?
见下篇博客的分析……
相关文章推荐
- 彰显程序的美丽与魅力——Ajax系列之四之错误处理
- 给Ajax一个漂亮的嫁衣——Ajax系列之五(下)之序列化和反序列化
- JQuery以POST方法从ASP.NET服务器获取Json数据完整示例
- Newtonsoft.Json(Json.Net)学习笔记
- powerdesigner逆向工程,从数据库导出PDM
- 利用 EncloseJS 来打包、加密和保护 Node.js 代码
- 菜鸟的B4A(B4X)开发成长日志
- 互聯網服務端技術——如何學
- 前端做些什么?如何学好前端
- 面试题数组篇(1)
- 学习Quartz(2)
- Gradle
- ThinkSNS入门基础
- ps aux命令显示的状态列中的Ss+,Rsl,R+,S<sl都是什么意思呢?
- 生产环境MySQL快速备份工具XtraBackup使用案例
- NodeJS学习——URL
- NodeJS学习——Query String
- XAMPP配置Apache禁止通过IP直接访问网站
- 配置Apache禁止访问网站目录
- Brackets-Git