DataTable循环引用错误?——Ajax系列之五(上)

    何谓循环引用?

    举个例子来说吧,一个男孩类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来解决循环问题。

    核心的思路原理:

    破解循环引用的核心思想是:在访问对方类之前,打破原有的引用关系,重新来指定对方类的引用。

 

=======================================================================================

 

    接下来进入代码实现部分:   

    

    默认情况下,如果在Ajax中返回一个DataTable,那么会弹出上图的错误提示。

 

    解决方法是:

    首先,在程序的Bin目录下添加Microsoft.Web.Preview.dll对象的引用

   

    然后,在配置文件的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();" />


运行效果图:

技术学习:

在客户端使用了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)));方法添加列字段。

如何解决自定义复杂数据类型的循环引用?

见下篇博客的分析……

转载于:https://my.oschina.net/star496481/blog/679888

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值