Ajax最强悍的功能莫过于服务器和客户端之间的异步交互,他们在交互的时候不是通过soap协议等,而是通过回调函数,以Json的格式传送数据。
由于Json格式的限制,在很多情况下,稍微复杂一些的数据往往会引起循环引用的错误,至于什么是循环引用?什么时候会发生循环引用?这里不再赘述,详见上篇博客。
都在强调Ajax的强大,那么就举这么一个例子:自定义一个复杂类型的数据,一个男孩类和一个女孩类互为对象,在客户端访问的时候就会出现循环引用,初学的我们或许会感叹:Ajax也不过如此嘛!其实不然,Ajax早已做好了解决这个问题的方法,那就是——序列化和反序列化!个人觉得它就好比一副穿在Json数据格式上的漂亮嫁衣,让程序猿们对Ajax青睐有嘉……
上一篇博客中总结了微软已经为常用的dt家族(datatable、dataset、datarow)的序列化和反序列化的封装;这里让我们为自定义的数据类型定制一套自己的嫁衣吧!
首先我们需要考虑这么几个问题:怎么来序列化和反序列化?什么时候需要序列化和反序列化?接下来就让每一个步代码来解释这些问题,希望看完这篇文章这几个问题可以迎刃而解。
==============================================================================================================================================================================
一、材料准备——循环引用的两个类的定义
1、在服务端App_Code目录下添加ComplexType文件夹下创建BoyAndGirl.cs类文件。
在BoyAndGirl.cs类文件中添加如下代码,定义Boy和Girl类,并指定可以相互访问。
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
namespace ComplexType
{
// 如果一个类型没有无参数的构造函数,那么也需要定义JavaScriptConverter,否则ASP.NET AJAX无法对其进行反序列化操作。
public class Boy
{
public string Name;
public Girl GirlFriend;
}
public class Girl
{
public string Name;
public Boy BoyFriend;
}
}
2、添加BoyGirlService.asmx服务,并在服务中创建Boy类和Girl类的循环引用。
using System;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Web.Script.Services;
using ComplexType;
using System.Diagnostics;
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ScriptService]
public class BoyGirlService : System.Web.Services.WebService {
[WebMethod]
//建立循环引用
public Boy GetBoyWithGirlFriend()
{
Boy boy = new Boy();
boy.Name = "Terry";
Girl girl = new Girl();
girl.Name = "Marry";
boy.GirlFriend = girl;
girl.BoyFriend = boy;
return boy;
}
[WebMethod]
//定义一个在服务器端返回客户端一些字串的方法
public string SetBoyWithGirlFriend(Boy boy)
{
//服务器端检测循环引用,如果不满足循环引用的话,会抛出异常
//boy.GirlFriend.BoyFriend判断方式是不是觉得有点怪
Debug.Assert(boy == boy.GirlFriend.BoyFriend);
//客户端使用该方法,解析boy对象,返回相关的信息字串
return String.Format(
"It's {0}, his girlfriend is {1}",
boy.Name, boy.GirlFriend.Name);
}
}
现在我们已经在服务端定义了Boy类和Girl类,并在asmx文件中定义了可以让客户端Ajax的脚本调用的循环引用的方法。嫁衣的材料已经准备完毕。
二、嫁衣制作——自定义序列化和反序列化
有了App_Code下的Boy类、Girl类的定义以及asmx中的循环引用的方法GetBoyWithGirlFriend,接下来,就着手DIY我们的嫁衣吧。
在App_Code目录下添加Converter文件夹,并在该文件夹下创建BoyConverter.cs类,封装序列化的反序列化的方法。
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Web.Script.Serialization;
using System.Collections.Generic;
using ComplexType;
namespace Converter
{
public class BoyConverter : JavaScriptConverter
{
/// <summary>
/// 服务器端自定义序列化,服务器端首先要检查回传的参数是否有循环引用,与BoyGirlService.asmx服务器端的Assert方法共同保证了服务器端的完整性。
/// </summary>
/// <param name="dictionary"></param>
/// <param name="type"></param>
/// <param name="serializer"></param>
/// <returns></returns>
public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
{
Boy boy = new Boy();
boy.Name = (string)dictionary["Name"];
//反序列化
boy.GirlFriend = serializer.ConvertToType<Girl>(dictionary["GirlFriend"]);
//重新建立起BoyFriend和Girlfriend之间的循环引用
boy.GirlFriend.BoyFriend = boy;
return boy;
}
/// <summary>
/// 自定义数据类型的序列化,这里要在web.config中的converters节点(相当于是一个路标)中,注册定义的序列化
/// </summary>
/// <param name="obj"></param>
/// <param name="serializer"></param>
/// <returns></returns>
public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
{
Boy boy = (Boy)obj;
//json字串是一个json对象的字串表现形式,json对象是使用字典和列表(dictionary和list)两种结构互相嵌套、引用的方法来表示的对象;对于每一个对象来说,我们都可以想象成是一个字典,由key和value组成,一个key个value组成一个item;一个json对象可以有多个item;
//先定义一个空的字典,返回的是一个字典,字典内部有两个项,一个是Name一个是GrilFriend,
IDictionary<string, object> result = new Dictionary<string, object>();
result["Name"] = boy.Name;
//先打乱Boy对象的GirlFriend原有的循环引用,或者说是先解开BoyFriend和GirlFriend之间的循环引用
boy.GirlFriend.BoyFriend = null;
//因为Girl有循环引用,所以,不能使用默认的方式输出,需要先打乱Boy对象的GirlFriend原有的循环引用
result["GirlFriend"] = boy.GirlFriend;
return result;
}
public override IEnumerable<Type> SupportedTypes
{
get
{
//yield 关键字向编译器指示它所在的方法是迭代器块。
//在迭代器块中, yield 关键字与 return 关键字结合使用,向枚举器对象提供值。
//yield 关键字也可与 break 结合使用,表示迭代结束。
yield return typeof(Boy);
}
}
}
}
这里突出总结一些我对Json、字典的概念的理解:
json字串是一个json对象的字串表现形式,json对象是使用字典和列表(dictionary和list)两种结构互相嵌套、引用的方法来表示的对象;对于每一个对象来说,我们都可以想象成是一个字典,由key和value组成,一个key个value组成一个item;一个json对象可以有多个item。
三、天使降临——客户端调用
这里只贴出客户端的javascript脚本:
<script language="javascript" type="text/javascript">
function getBoy() {
//调动服务端的方法,显示相关信息
BoyGirlService.GetBoyWithGirlFriend(onGetBoySucceeded, onFailed);
}
function onGetBoySucceeded(result) {
//下面这句话是重新建立起BoyFriend和Girlfriend之间的循环引用,因为在服务器端已经解开了循环引用
// result.GirlFriend.BoyFriend = result;
alert(String.format(
"It's {0}, his girlfriend is {1}",
result.Name,
result.GirlFriend.Name));
}
function onFailed(error)
{
alert(error.get_message());
}
function setBoy()
{
var boy = new Object();
boy.Name = "Terry";
var girl = new Object();
girl.Name = "Mary";
boy.GirlFriend = girl;
//调用服务端的方法,传入参数
BoyGirlService.SetBoyWithGirlFriend(boy, onSetBoySucceeded, onFailed);
}
function onSetBoySucceeded(result)
{
alert(result);
}
</script>
这样我们就自制了一套序列化和反序列化的嫁衣,来看一下运行效果:
技术思想总结——怎么来序列化和反序列化?
回顾一下序列化和反序列化的思路就是:在服务端先打乱Boy对象的GirlFriend原有的循环引用,或者说是先解开BoyFriend和GirlFriend之间的循环引用,然后重新建立起BoyFriend和Girlfriend之间的循环引用。
怎么打乱循环引用?核心的代码就是将对象属性赋值为空后,重新赋值即可:
//先打乱Boy对象的GirlFriend原有的循环引用,或者说是先解开BoyFriend和GirlFriend之间的循环引用
boy.GirlFriend.BoyFriend = null;
//因为Girl有循环引用,所以,不能使用默认的方式输出,需要先打乱Boy对象的GirlFriend原有的循环引用
result["GirlFriend"] = boy.GirlFriend;
视野拓展——新知识学习: 泛化的字典数据类型和泛化的枚举的使用
在序列化的时候,使用的是IDictionary<>的泛化类型,传入一个obj对象,然后经过序列化后返回的result是一个IDictionary类型。其他类型的自定义数据类型,也可以借用该思路。
反序列化基本上是一个相反的步骤,传入IDictionary类型,返回obj对象类型。 result和obj对象都由key和value组成。
另外,如果需要我们还可以在客户端重新添加解开后的循环引用。
//下面这句话是重新建立起BoyFriend和Girlfriend之间的循环引用,因为在服务器端已经解开了循环引用
// result.GirlFriend.BoyFriend = result;
补充说明:
因为用到了泛化和序列化反序列化,需要添加相应的引用:
using System.Web.Script.Serialization;
using System.Collections.Generic;
--------------------------------------------------------------------------------------------------------欢迎交流,如有理解错误,欢迎斧正!
分享到:
相关推荐
ssh2 试用ajax序列化及反序列化案例
c#序列化的实例,ajax返回一个数据集
本文介绍了Java对象序列化的五种方式,并提供了选择最适合应用程序的数据格式和技术所需要的全部信息。这篇文章侧重于可以用来生成 Java对象以数据为中心的视图的技术。演示可以把 JavaBeans变成XML文档的各种方法,...
ASP.NET AJAX深入浅出系列课程(5):客户端访问WebService(中):参数类型的序列化与反序列化
ASP.NET AJAX深入浅出系列课程(5):客户端访问WebService(中):参数类型的序列化与反序列化
随着Ajax的出现,表单序列化已经成为一种需求,在学习原生Ajax时,若用POST方法向后台提交数据时,就需要将表单序列化 在JavaScript中可以利用表单字段的type属性,连同name和value属性,一起实现表单的序列化。 在进行...
// [AjaxMethod(Encode = EncryptType.Base64, Description = "反序列化User")] User Login(string name,string password){ } } } 例二: using CH2; public class Handler : AjaxHandler...
ASP.NET AJAX框架编程之JSON序列化剖析
提出了一种基于JSON的对象序列化算法,该算法通过分析JSON文法并建立对象导航图,透明地将Java对象序列化成JSON表达式,使客户端能够很好地利用JavaScript引擎来解析JSON响应,有效地解决了解析XML所造成的缺陷。
SerializingJSON.aspx 序列化和反序列化的JSON,包含一些常用属性说明 SerializingJSONFragments.aspx 部分片段的序列化的JSON及查询 Scripts\ 常用javascript脚本文件夹 jquery-1.4.1-vsdoc.js jquery...
jQuery 3.1 标准课程第九章 Ajax序列化事件
关于AJAX 所谓Ajax,全名Asynchronous JavaScript and XML。(也就异步的JS和XML) 简单点来讲就是不刷新页面来发送和获取数据,然后更新页面。 Ajax的优势 •无需插件支持 •优秀的用户体验 •提高web程序的性能...
比如我们经常这样写一个ajax的post请求: $.ajax({ type: "post", // post or get contentType:"application/json;charset=utf-8", data: “requestTag=”+tag+"&content="+content, //请求参数 url: "po
第 13 部分:面向 Java 开发人员的 Ajax: Ajax 的 Java 对象序列化 第 14部分:面向 Java 开发人员的 Ajax 结合 Direct Web Remoting 使用 Ajax 第 15部分:面向 Java 开发人员的 Ajax: 探索 Google Web Toolkit
用PHP做的简单留言板, 原本打算不用数据库的,可是后来时间有限,就在数据库上面建了一个留言表,其他的数据全部用php对象序列化以文件的形式存储的,没有怎么写过B/S系统,用php也很少,这里面主页面全部用ajax实现的,...
本系列的作者是一位 Ajax 专家,他演示了这些技术如何协同工作 —— 从总体概述到细节的讨论 —— 使高效的 Web 开发成为现实。他还揭开了 Ajax 核心概念的神秘面纱,包括 XMLHttpRequest 对象。 五年前,如果不...
封装好的Jquery 的ajax 的json的AutoComplete控件(用户控件),json序列化也做好了,拎包入住
服务器端采用 MC 设计模式,Controler 自下而上分为:收发模块、编码模块、加密解密模块、序列化/反序列化模块、主处理模块(包含 DAO);其中加密解密模块,由于 js 支持不好,预留暂不使用; 客户端使用 AJAX 心跳...
先回顾一下Ajax技术引入对传统Web开发挑战: <br> n 开发方式模糊 <br> ...针对传输的性能、数据的格式、序列化的深度、数据的解 析与展现等诸多复杂问题必须要有一套满足开发需求的良好解决方案。