zoukankan      html  css  js  c++  java
  • 给Ajax一个漂亮的嫁衣——Ajax系列之五(下)之序列化和反序列化

    给Ajax一个漂亮的嫁衣——Ajax系列之五(下)之序列化和反序列化

    标签: ajaxdictionaryjsonobject服务器function
     分类:
     

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

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

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

                

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

        

       

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

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

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

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

        

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

       

    [csharp] view plain copy
     
    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.   
    11. namespace ComplexType  
    12. {  
    13.       
    14.     // 如果一个类型没有无参数的构造函数,那么也需要定义JavaScriptConverter,否则ASP.NET AJAX无法对其进行反序列化操作。  
    15.     public class Boy  
    16.     {  
    17.         public string Name;  
    18.   
    19.         public Girl  GirlFriend;  
    20.     }  
    21.   
    22.       
    23.     public class Girl  
    24.     {  
    25.         public string Name;  
    26.   
    27.         public Boy BoyFriend;  
    28.     }  
    29. }</span>  


       

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

       

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


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

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

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

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

       

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

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

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

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

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

       

    [javascript] view plain copy
     
    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.                   
    10.                 alert(String.format(  
    11.                     "It's {0}, his girlfriend is {1}",  
    12.                     result.Name,  
    13.                     result.GirlFriend.Name));  
    14.             }  
    15.               
    16.             function onFailed(error)  
    17.             {  
    18.                 alert(error.get_message());  
    19.             }  
    20.               
    21.             function setBoy()  
    22.             {  
    23.                 var boy = new Object();  
    24.                 boy.Name = "Terry";  
    25.                 var girl = new Object();  
    26.                 girl.Name = "Mary";  
    27.                 boy.GirlFriend = girl;  
    28.                 //调用服务端的方法,传入参数  
    29.                 BoyGirlService.SetBoyWithGirlFriend(boy, onSetBoySucceeded, onFailed);  
    30.             }  
    31.             function onSetBoySucceeded(result)  
    32.             {  
    33.                 alert(result);  
    34.             }  
    35. </script></span>  

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

        

       

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

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

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

       

    [csharp] view plain copy
     
    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组成。

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

       

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


     

    补充说明:

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

    [csharp] view plain copy
     
    1. using System.Web.Script.Serialization;  
    2. using System.Collections.Generic;  
  • 相关阅读:
    KindEditor编辑器的使用
    导航栏
    ajax php 验证注册用户名是否存在
    PS照片改底色
    截取邮箱@后面内容的两种情况
    js导航栏单击事件背景颜色变换
    model中的自动验证 $_validate $_auto
    一对一关联模型,HAS_ONE
    一对多关联模型,BELONGS_TO
    C++操作MySQL数据库
  • 原文地址:https://www.cnblogs.com/zxtceq/p/5403425.html
Copyright © 2011-2022 走看看