2012-07-25 18:41 2242人阅读 评论(6) 收藏 举报
 分类:
Ajax(6) 

版权声明:本文为博主原创文章,未经博主允许不得转载。

Ajax最强悍的功能莫过于服务器和客户端之间的异步交互,他们在交互的时候不是通过soap协议等,而是通过回调函数,以Json的格式传送数据。

由于Json格式的限制,在很多情况下,稍微复杂一些的数据往往会引起循环引用的错误,至于什么是循环引用?什么时候会发生循环引用?这里不再赘述,详见上篇博客

都在强调Ajax的强大,那么就举这么一个例子:自定义一个复杂类型的数据,一个男孩类和一个女孩类互为对象,在客户端访问的时候就会出现循环引用,初学的我们或许会感叹:Ajax也不过如此嘛!其实不然,Ajax早已做好了解决这个问题的方法,那就是——序列化和反序列化!个人觉得它就好比一副穿在Json数据格式上的漂亮嫁衣,让程序猿们对Ajax青睐有嘉……

上一篇博客中总结了微软已经为常用的dt家族(datatable、dataset、datarow)的序列化和反序列化的封装;这里让我们为自定义的数据类型定制一套自己的嫁衣吧!

首先我们需要考虑这么几个问题:怎么来序列化和反序列化?什么时候需要序列化和反序列化?接下来就让每一个步代码来解释这些问题,希望看完这篇文章这几个问题可以迎刃而解。

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

一、材料准备——循环引用的两个类的定

1、在服务端App_Code目录下添加ComplexType文件夹下创建BoyAndGirl.cs类文件。

在BoyAndGirl.cs类文件中添加如下代码,定义Boy和Girl类,并指定可以相互访问。

  1. <span style="font-size:18px;">using System;
  2. using System.Data;
  3. using System.Configuration;
  4. using System.Web;
  5. using System.Web.Security;
  6. using System.Web.UI;
  7. using System.Web.UI.WebControls;
  8. using System.Web.UI.WebControls.WebParts;
  9. using System.Web.UI.HtmlControls;
  10. namespace ComplexType
  11. {
  12. // 如果一个类型没有无参数的构造函数,那么也需要定义JavaScriptConverter,否则ASP.NET AJAX无法对其进行反序列化操作。
  13. public class Boy
  14. {
  15. public string Name;
  16. public Girl  GirlFriend;
  17. }
  18. public class Girl
  19. {
  20. public string Name;
  21. public Boy BoyFriend;
  22. }
  23. }</span>

   

    2、添加BoyGirlService.asmx服务,并在服务中创建Boy类和Girl类的循环引用。

  1. <span style="font-size:18px;">using System;
  2. using System.Web;
  3. using System.Web.Services;
  4. using System.Web.Services.Protocols;
  5. using System.Web.Script.Services;
  6. using ComplexType;
  7. using System.Diagnostics;
  8. [WebService(Namespace = "http://tempuri.org/")]
  9. [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
  10. [ScriptService]
  11. public class BoyGirlService  : System.Web.Services.WebService {
  12. [WebMethod]
  13. //建立循环引用
  14. public Boy GetBoyWithGirlFriend()
  15. {
  16. Boy boy = new Boy();
  17. boy.Name = "Terry";
  18. Girl girl = new Girl();
  19. girl.Name = "Marry";
  20. boy.GirlFriend = girl;
  21. girl.BoyFriend = boy;
  22. return boy;
  23. }
  24. [WebMethod]
  25. //定义一个在服务器端返回客户端一些字串的方法
  26. public string SetBoyWithGirlFriend(Boy boy)
  27. {
  28. //服务器端检测循环引用,如果不满足循环引用的话,会抛出异常
  29. //boy.GirlFriend.BoyFriend判断方式是不是觉得有点怪
  30. Debug.Assert(boy == boy.GirlFriend.BoyFriend);
  31. //客户端使用该方法,解析boy对象,返回相关的信息字串
  32. return String.Format(
  33. "It's {0}, his girlfriend is {1}",
  34. boy.Name, boy.GirlFriend.Name);
  35. }
  36. }</span>

现在我们已经在服务端定义了Boy类和Girl类,并在asmx文件中定义了可以让客户端Ajax的脚本调用的循环引用的方法。嫁衣的材料已经准备完毕。

二、嫁衣制作——自定义序列化和反序列化

有了App_Code下的Boy类、Girl类的定义以及asmx中的循环引用的方法GetBoyWithGirlFriend,接下来,就着手DIY我们的嫁衣吧。

在App_Code目录下添加Converter文件夹,并在该文件夹下创建BoyConverter.cs类,封装序列化的反序列化的方法。

  1. <span style="font-size:18px;">using System;
  2. using System.Data;
  3. using System.Configuration;
  4. using System.Web;
  5. using System.Web.Security;
  6. using System.Web.UI;
  7. using System.Web.UI.WebControls;
  8. using System.Web.UI.WebControls.WebParts;
  9. using System.Web.UI.HtmlControls;
  10. using System.Web.Script.Serialization;
  11. using System.Collections.Generic;
  12. using ComplexType;
  13. namespace Converter
  14. {
  15. public class BoyConverter : JavaScriptConverter
  16. {
  17. /// <summary>
  18. /// 服务器端自定义序列化,服务器端首先要检查回传的参数是否有循环引用,与BoyGirlService.asmx服务器端的Assert方法共同保证了服务器端的完整性。
  19. /// </summary>
  20. /// <param name="dictionary"></param>
  21. /// <param name="type"></param>
  22. /// <param name="serializer"></param>
  23. /// <returns></returns>
  24. public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
  25. {
  26. Boy boy = new Boy();
  27. boy.Name = (string)dictionary["Name"];
  28. //反序列化
  29. boy.GirlFriend = serializer.ConvertToType<Girl>(dictionary["GirlFriend"]);
  30. //重新建立起BoyFriend和Girlfriend之间的循环引用
  31. boy.GirlFriend.BoyFriend = boy;
  32. return boy;
  33. }
  34. /// <summary>
  35. /// 自定义数据类型的序列化,这里要在web.config中的converters节点(相当于是一个路标)中,注册定义的序列化
  36. /// </summary>
  37. /// <param name="obj"></param>
  38. /// <param name="serializer"></param>
  39. /// <returns></returns>
  40. public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
  41. {
  42. Boy boy = (Boy)obj;
  43. //json字串是一个json对象的字串表现形式,json对象是使用字典和列表(dictionary和list)两种结构互相嵌套、引用的方法来表示的对象;对于每一个对象来说,我们都可以想象成是一个字典,由key和value组成,一个key个value组成一个item;一个json对象可以有多个item;
  44. //先定义一个空的字典,返回的是一个字典,字典内部有两个项,一个是Name一个是GrilFriend,
  45. IDictionary<string, object> result = new Dictionary<string, object>();
  46. result["Name"] = boy.Name;
  47. //先打乱Boy对象的GirlFriend原有的循环引用,或者说是先解开BoyFriend和GirlFriend之间的循环引用
  48. boy.GirlFriend.BoyFriend = null;
  49. //因为Girl有循环引用,所以,不能使用默认的方式输出,需要先打乱Boy对象的GirlFriend原有的循环引用
  50. result["GirlFriend"] = boy.GirlFriend;
  51. return result;
  52. }
  53. public override IEnumerable<Type> SupportedTypes
  54. {
  55. get
  56. {
  57. //yield 关键字向编译器指示它所在的方法是迭代器块。
  58. //在迭代器块中, yield 关键字与 return 关键字结合使用,向枚举器对象提供值。
  59. //yield 关键字也可与 break 结合使用,表示迭代结束。
  60. yield return typeof(Boy);
  61. }
  62. }
  63. }
  64. }</span>

这里突出总结一些我对Json、字典的概念的理解:

    json字串是一个json对象的字串表现形式,json对象是使用字典和列表(dictionary和list)两种结构互相嵌套、引用的方法来表示的对象;对于每一个对象来说,我们都可以想象成是一个字典,由key和value组成,一个key个value组成一个item;一个json对象可以有多个item。

三、天使降临——客户端调用

这里只贴出客户端的javascript脚本:

  1. <span style="font-size:18px;"><script language="javascript" type="text/javascript">
  2. function getBoy() {
  3. //调动服务端的方法,显示相关信息
  4. BoyGirlService.GetBoyWithGirlFriend(onGetBoySucceeded, onFailed);
  5. }
  6. function onGetBoySucceeded(result) {
  7. //下面这句话是重新建立起BoyFriend和Girlfriend之间的循环引用,因为在服务器端已经解开了循环引用
  8. // result.GirlFriend.BoyFriend = result;
  9. alert(String.format(
  10. "It's {0}, his girlfriend is {1}",
  11. result.Name,
  12. result.GirlFriend.Name));
  13. }
  14. function onFailed(error)
  15. {
  16. alert(error.get_message());
  17. }
  18. function setBoy()
  19. {
  20. var boy = new Object();
  21. boy.Name = "Terry";
  22. var girl = new Object();
  23. girl.Name = "Mary";
  24. boy.GirlFriend = girl;
  25. //调用服务端的方法,传入参数
  26. BoyGirlService.SetBoyWithGirlFriend(boy, onSetBoySucceeded, onFailed);
  27. }
  28. function onSetBoySucceeded(result)
  29. {
  30. alert(result);
  31. }
  32. </script></span>

这样我们就自制了一套序列化和反序列化的嫁衣,来看一下运行效果:

技术思想总结——怎么来序列化和反序列化?

回顾一下序列化和反序列化的思路就是:在服务端先打乱Boy对象的GirlFriend原有的循环引用,或者说是先解开BoyFriend和GirlFriend之间的循环引用,然后重新建立起BoyFriend和Girlfriend之间的循环引用。

怎么打乱循环引用?核心的代码就是将对象属性赋值为空后,重新赋值即可:

  1. <span style="font-size:18px;">//先打乱Boy对象的GirlFriend原有的循环引用,或者说是先解开BoyFriend和GirlFriend之间的循环引用
  2. boy.GirlFriend.BoyFriend = null;
  3. //因为Girl有循环引用,所以,不能使用默认的方式输出,需要先打乱Boy对象的GirlFriend原有的循环引用
  4. result["GirlFriend"] = boy.GirlFriend;</span>

视野拓展——新知识学习: 泛化的字典数据类型和泛化的枚举的使用

在序列化的时候,使用的是IDictionary<>的泛化类型,传入一个obj对象,然后经过序列化后返回的result是一个IDictionary类型。其他类型的自定义数据类型,也可以借用该思路。

反序列化基本上是一个相反的步骤,传入IDictionary类型,返回obj对象类型。 result和obj对象都由key和value组成。

另外,如果需要我们还可以在客户端重新添加解开后的循环引用。

  1. <span style="font-size:18px;">//下面这句话是重新建立起BoyFriend和Girlfriend之间的循环引用,因为在服务器端已经解开了循环引用
  2. // result.GirlFriend.BoyFriend = result;</span>

补充说明:

因为用到了泛化和序列化反序列化,需要添加相应的引用:

  1. using System.Web.Script.Serialization;
  2. using System.Collections.Generic;

给Ajax一个漂亮的嫁衣——Ajax系列之五(下)之序列化和反序列化的更多相关文章

  1. Java基础系列(八)序列化与反序列化

    先来看两个例子 示例一:将对象保存成字节数组,再把对象的字节数组还原为对象 示例中用到的Bean package com.huawei.beans; import java.io.Serializab ...

  2. ajax 一个 gbk 目标后内容乱码的解决方案

    ajax 一个 gbk 目标后,如果内容出现乱码,说明服务器在送出内容时没有指定 charset,ajax 对于没有指定 charset 的 response 默认以 utf-8 来处理,所有出现乱码 ...

  3. 一个jquery-ajax post例子ajax 登陆

    index.html文件 <html> <head> <meta http-equiv="Content-Type" content="te ...

  4. 封装一个类似jquery的ajax方法

    //封装一个类似jquery的ajax方法,当传入参数,就可以发送ajax请求 //参数格式如下{ // type:"get"/"post", // dataT ...

  5. ajax一个很好的加载效果

    推荐一个常用的jquery加载效果插件: 要引入这个插件的css和js: <link href="<%=path %>/css/showLoading.css" ...

  6. jquery ajax一个坑爹的问题

    问题描述: jquery ajax dataType为json时,如果json数据不严格,不进入success方法,控制台也不会报错. data.json {"result":&q ...

  7. 商品类型的下拉框绑定一个事件,通过ajax获取属性

    html代码这么写 <!-- 商品属性 --> <table cellspacing="1" cellpadding="3" width=&q ...

  8. 掌握 Ajax,第 1 部分: Ajax 入门简介

    转:http://www.ibm.com/developerworks/cn/xml/wa-ajaxintro1.html 掌握 Ajax,第 1 部分: Ajax 入门简介 理解 Ajax 及其工作 ...

  9. python 全栈开发,Day75(Django与Ajax,文件上传,ajax发送json数据,基于Ajax的文件上传,SweetAlert插件)

    昨日内容回顾 基于对象的跨表查询 正向查询:关联属性在A表中,所以A对象找关联B表数据,正向查询 反向查询:关联属性在A表中,所以B对象找A对象,反向查询 一对多: 按字段:xx book ----- ...

随机推荐

  1. Linux进程间通信--使用信号量【转】

    本文转载自:http://blog.csdn.net/ljianhui/article/details/10243617 这篇文章将讲述别一种进程间通信的机制——信号量.注意请不要把它与之前所说的信号 ...

  2. Wannafly 挑战赛22 D 整数序列 线段树 区间更新,区间查询

    题目链接:https://www.nowcoder.com/acm/contest/160/D 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 262144K,其他语言524288K ...

  3. 处理文字基线 文字对不齐 font-size

    这是我无意中发现的,先记录下 比如你在一个h1标签里面添加文字,或者在其他块级标签添加文字,想让他们间隙少一点,(基线影响)可把行高设置为line-height: 1;就达到消除基线的作用. 建议使用 ...

  4. hdoj-2086-A1=?

    题目:A1=? 代码(作者:Fistice): #include<cstdio> #include<cmath> #include<cstring> #includ ...

  5. 纯CSS实现一个微信logo,需要几个标签?

    博客已迁移至http://lwzhang.github.io. 纯CSS实现一个微信logo并不难,难的是怎样用最少的html标签实现.我一直在想怎样用一个标签就能实现,最后还是没想出来,就只好用两个 ...

  6. JavaScript 问题解决 -- parseInt("08")或parseInt("09")转换返回0的解决方法

      不小心范了一个低级错误,这个问题也是很多初学者容易忽略滴,它就是js中的整数转换函数parseInt(string, radix). 使用parseInt转换"01" - &q ...

  7. JS中Ajax的同步和异步

    ajax同步 : 意味着此时请求Server后,JS代码不再继续执行,等待Server返回后才继续往下执行. ajax异步 : 意味着此时请求Server后,JS代码继续执行,不管Server什么时候 ...

  8. xinwenti

    angularjs  angular2脏检查机制和数据双向绑定远离 angular2 aot编译

  9. Python mysql-表的创建,删除和更新

    2017-09-06 20:59:56 数据库的创建 CREATE DATEBASE <数据库的名称> 表的创建 CREATE TABLE <表名> (<列名1> ...

  10. 增加centos7.3上安装php7的php-soap扩展

    代码传到正式服务器上去就:Class 'SoapClient' not found,只能是soap扩展没装!    因为服务器上面的PHP是7.1.11的,所以soap也要装7.1.11的,否则会冲突 ...