好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

序列化DataContractSerializer

序列化DataContractSerializer

wcf基础教程之 数据契约的序列化DataContractSerializer

上一篇博客我们说明了数据契约的前身Xml的序列化,这次还是言归正传,回到wcf的技术上来,分析一下DataContractSerializer 。

首先我们必须了解wcf默认是通过xml进行数据传输,但是并不意味着就一定要用这种,还有轻量级的json。DataContractSerializer继承自XmlObjectSerializer,是可以直接对.Net对象进行序列化操作,但是DatacontractSerializer的使用更加方便。

要使一个类成为数据契约,我们必须要通过DataContractAttribute进行标注,然后通过应用DataMemberAttribute特性来标注它的属性或字段,才可以让这个类成为一个数据契约,在网络间进行传输。

DataContract的属性很少,但是都特别有用,在序列化的时候有一个属性 IsReference ,表示在进行序列化的时候是否要保持对象现有的引用结构,默认值为false。 这个属性在我们进行序列化的时候会举例说明其中的区别。

DataMember的属性也很少,IsRequired 表示是否是必须的,默认值为false。这个属性是什么意思呢?就是说在序列化的时候这个属性如果不提供,则会报错,或者在反序列化的时候,如果这个属性没有,那么也会报错,总之就是必须这个属性存在。

DataMember还有一个属性EmitDefaultValue,表示数据成员的值等于默认值的情况下,是否还需要将其序列化到xml中,默认值为true,表示总是将其序列化。

我提出一个问题?就是如何计算wcf的默认可以处理的对象个数?因为如果我们创建很多的对象进行序列化,那么可能会出现一个超出处理对象最大值的异常信息?这个也是我们必须要考虑的。

在数据契约中,还存在一种特殊的,我们叫做已知类型 KnownType。因为wcf在序列化和反序列化的时候,必须明确的知道对象的类型。这个放到下一篇我们来讨论什么时候会用到已知类型。

定义一个数据契约是那么的简单,以至于我们总是认为wcf还是那么的容易。请记住这么一句话,师傅领进门,修行在个人。入门简单这是师傅的功劳,但是修行怎么样,就要看你自己的造化了。

  1   using   System;
   2   using   System.Collections.Generic;
   3   using   System.Linq;
   4   using   System.Text;
   5   using   System.Runtime.Serialization;
   6  
  7   namespace   Chinaer.WcfDemo.Contracts
   8   {
   9       [DataContract]
  10       public   class   Person
  11       {
  12           [DataMember]
  13           public   string  ID {  get ;  set  ; }
  14  
 15           public   string  UserName {  get ;  set  ; }
  16  
 17           [DataMember]
  18           ///   <summary> 
 19           ///   私有属性
  20           ///   </summary> 
 21           private   string  UserPwd {  get ;  set  ; }
  22  
 23           //  公有字段 
 24           [DataMember]
  25           public   string   ParentName;
  26           //  私有字段 
 27           [DataMember]
  28           private   string   BrotherName;
  29  
 30       }
  31  }

我们仍然在控制台进行输出到xml文件查看他们的区别。

  1    static   void  Main( string  [] args)
   2           {
   3              Chinaer.WcfDemo.Contracts.PersonName person= new   Contracts.PersonName(){ 
   4                  ID= "  1  " , ParentName= "  parent  " , UserName= "  guohz  " 
  5               };
   6              DataContractSerialize<Contracts.PersonName>(person,  "  person.xml  "  );
   7               Console.Read();
   8           }
   9           ///   <summary> 
 10           ///   DataContractSerializer序列化
  11           ///   </summary> 
 12           ///   <typeparam name="T"></typeparam> 
 13           ///   <param name="instance"></param> 
 14           ///   <param name="fileName"></param> 
 15           public   static   void  DataContractSerialize<T>(T instance,  string   fileName)
  16           {
  17              DataContractSerializer serializer =  new  DataContractSerializer( typeof  (Chinaer.WcfDemo.Contracts.PersonName));
  18               using  (XmlWriter writer =  new   XmlTextWriter(fileName, Encoding.UTF8))
  19               {
  20                   serializer.WriteObject(writer, instance);
  21  
 22               }
  23               Process.Start(fileName);
  24          }

数据契约序列化除了序列化器不同之外,其他的代码步骤都相同。生成的xml文件。

 1   <  PersonName   xmlns:i  ="http://www.w3.org/2001/XMLSchema-instance"  
 2       xmlns  ="http://schemas.datacontract.org/2004/07/Chinaer.WcfDemo.Contracts"  > 
 3       <  BrotherName   i:nil  ="true"   /> 
 4       <  ID  > 1 </  ID  > 
 5       <  ParentName  > parent </  ParentName  > 
 6       <  UserPwd   i:nil  ="true"   /> 
 7   </  PersonName  > 

大家注意:上面生成的xml我们可以看出,无论是公有属性,还有私有属性或私有字段,只要加上了DataMember attribute,那么就会被序列化。

现在我们来想一下,如果有主从关系的两个类,最后序列化会生成什么呢?动手试试吧。

我们再次定义一个类继承自刚才定义的类,然后我们序列化子类,我们一起来查看结果。

  1   using   System;
   2   using   System.Collections.Generic;
   3   using   System.Linq;
   4   using   System.Text;
   5   using   System.Runtime.Serialization;
   6  
  7   namespace   Chinaer.WcfDemo.Contracts
   8   {
   9       [DataContract]
  10       public   class   PersonName
  11       {
  12           [DataMember]
  13           public   string  ID {  get ;  set  ; }
  14  
 15           public   string  UserName {  get ;  set  ; }
  16  
 17           [DataMember]
  18           ///   <summary> 
 19           ///   私有属性
  20           ///   </summary> 
 21           private   string  UserPwd {  get ;  set  ; }
  22  
 23           //  公有字段 
 24           [DataMember]
  25           public   string   ParentName;
  26           //  私有字段 
 27           [DataMember]
  28           private   string   BrotherName;
  29  
 30       }
  31  
 32       [DataContract]
  33       public   class   ParentName:PersonName
  34       {
  35           [DataMember]
  36           public   string  Parent {  get ;  set  ; }
  37       }
  38  
 39  }

序列化子类生成的xml为:

 1  <ParentName xmlns:i= "  http://www.w3.org/2001/XMLSchema-instance  "  
 2      xmlns= "  http://schemas.datacontract.org/2004/07/Chinaer.WcfDemo.Contracts  " >
 3      <BrotherName i:nil= "  true  "  />
 4      <ID> 1 </ID>
 5      <ParentName>parent</ParentName>
 6      <UserPwd i:nil= "  true  "  />
 7      <Parent>parent</Parent>
 8      </ParentName>

对比父类生成的xml,我们可以得出以下结论:

父类的属性在序列化成xml的时候在子节点的前面。 序列化中xml元素的排序时按照字母顺序排序。 子类序列化会吧父类一起序列化,并且序列化到子类中

对于第一点,可能这是我发现的一个规律,对于第二点,可能有朋友要说了,这只是看了一个就得出这个结论,有点草率,如果添加了order属性,那么肯定顺序会改变。对于第三个,应该说是常识,但是我在上面说过一个关于引用的问题,这个问题就和这个有关。

下面我们添加order属性,来再次查看生成的xml的结果。

  1   using   System;
   2   using   System.Collections.Generic;
   3   using   System.Linq;
   4   using   System.Text;
   5   using   System.Runtime.Serialization;
   6  
  7   namespace   Chinaer.WcfDemo.Contracts
   8   {
   9       [DataContract]
  10       public   class   PersonName
  11       {
  12          [DataMember(Order =  2  )]
  13           public   string  ID {  get ;  set  ; }
  14  
 15           public   string  UserName {  get ;  set  ; }
  16  
 17          [DataMember(Order =  1  )]
  18           ///   <summary> 
 19           ///   私有属性
  20           ///   </summary> 
 21           private   string  UserPwd {  get ;  set  ; }
  22  
 23           //  公有字段 
 24          [DataMember(Order = - 1  )]
  25           public   string   ParentName;
  26           //  私有字段 
 27          [DataMember(Order =  0  )]
  28           private   string   BrotherName;
  29  
 30       }
  31  
 32       [DataContract]
  33       public   class   ParentName : PersonName
  34       {
  35          [DataMember(Order =  1  )]
  36           public   string  Parent {  get ;  set  ; }
  37       }
  38  
 39  }

请注意上面的代码,我们为order赋值的时候,有赋值-1和0,子类我们赋值为1.那么根据order的作用,父类应该是按照order排序,子类的位置我们根据生成的xml文件来查看。

如果你是直接运行的话,那么你会得到如下的异常信息提示。

我们上面说过,特别注意我们为order赋值-1.其中我们的ParentName属性的order就是-1.如果我没记错的话,我们最好设置0以上的数字

 1  <ParentName xmlns:i= "  http://www.w3.org/2001/XMLSchema-instance  "  
 2      xmlns= "  http://schemas.datacontract.org/2004/07/Chinaer.WcfDemo.Contracts  " >
 3      <BrotherName i:nil= "  true  "  />
 4      <UserPwd i:nil= "  true  "  />
 5      <ID> 1 </ID>
 6      <ParentName>parent</ParentName>
 7      <Parent>parent</Parent>
 8      </ParentName>

加了order属性之后,xml元素的顺序果然改变了,但是请注意最后一个,仍然是子类的元素。所以请注意这个规律就可以。

下面我们来一起了解一下,如果类之间有引用关系,那么如果保持引用和不保持引用状态生成的xml有哪些不同呢?

我们取消personName和parentName的父子关系,然后重修修改序列化,添加是否需要保持引用状态的bool值。

  1    static   void  Main( string  [] args)
   2           {
   3              Chinaer.WcfDemo.Contracts.ParentName person =  new   Contracts.ParentName()
   4               {
   5                  Parent =  "  parent  " 
  6               };
   7              Chinaer.WcfDemo.Contracts.PersonName personName =  new   Contracts.PersonName()
   8               {
   9                  ID =  "  id  "  ,
  10                  ParentName =  person,
  11                  ParentName2 =  person,
  12                  UserName =  "  guozhiqi  " 
 13               };
  14              DataContractSerialize<Contracts.PersonName>(personName,  "  person.xml  " , true ); //  保持引用状态 
 15              DataContractSerialize<Contracts.PersonName>(personName,  "  person2.xml  " ,  false ); //  不保持引用状态 
 16               Console.Read();
  17           }
  18           ///   <summary> 
 19           ///   DataContractSerializer序列化
  20           ///   </summary> 
 21           ///   <typeparam name="T"></typeparam> 
 22           ///   <param name="instance"></param> 
 23           ///   <param name="fileName"></param> 
 24           public   static   void  DataContractSerialize<T>(T instance,  string  fileName,  bool   preserveReference)
  25           {
  26              DataContractSerializer serializer =  new  DataContractSerializer( typeof (Chinaer.WcfDemo.Contracts.ParentName),  null ,  int .MaxValue,  false , preserveReference,  null  );
  27               using  (XmlWriter writer =  new   XmlTextWriter(fileName, Encoding.UTF8))
  28               {
  29                   serializer.WriteObject(writer, instance);
  30  
 31               }
  32               Process.Start(fileName);
  33          }

保持对象引用状态生成的xml文件为:

  1  <PersonName xmlns:i= "  http://www.w3.org/2001/XMLSchema-instance  "  
  2      z:Id= "  1  "  xmlns:z= "  http://schemas.microsoft.com/2003/10/Serialization/  "  
  3      xmlns= "  http://schemas.datacontract.org/2004/07/Chinaer.WcfDemo.Contracts  " >
  4      <ParentName2 z:Id= "  2  " >
  5          <Parent z:Id= "  3  " >parent</Parent>
  6          </ParentName2>
  7          <BrotherName i:nil= "  true  "  />
  8          <UserPwd i:nil= "  true  "  />
  9          <ID z:Id= "  4  " >id</ID>
 10      <ParentName z:Ref= "  2  "  i:nil= "  true  "  />
 11      </PersonName>

不保持对象引用状态生成的xml文件为:

 1  <PersonName xmlns:i= "  http://www.w3.org/2001/XMLSchema-instance  "  
 2      xmlns= "  http://schemas.datacontract.org/2004/07/Chinaer.WcfDemo.Contracts  " >
 3      <ParentName2><Parent>parent</Parent></ParentName2>
 4      <BrotherName i:nil= "  true  "  />
 5      <UserPwd i:nil= "  true  "  />
 6      <ID>id</ID>
 7      <ParentName>
 8          <Parent>parent</Parent></ParentName>
 9      </PersonName>

我对xml理解的不深,无法准确的说出其中的区别,但是我看到了在不保持对象引用状态的情况下,对象引用了几次就会出现几次。我们可以得出这么一个结论,在大数据量的情况下,保持对象的引用状态可以减少传输的数据量。

刚才那个问题我们还没有回答?就是对象的个数如何计算?为了回答这个问题,我们来看一个例子

请注意我们的序列化代码:

  1           static   void  Main( string  [] args)
   2           {
   3              Chinaer.WcfDemo.Contracts.ParentName person =  new   Contracts.ParentName()
   4               {
   5                  Parent =  "  parent  " 
  6               };
   7              Chinaer.WcfDemo.Contracts.PersonName personName =  new   Contracts.PersonName()
   8               {
   9                  ID =  "  id  "  ,
  10                  ParentName =  person,
  11                  ParentName2 =  person,
  12                  UserName =  "  guozhiqi  " 
 13               };
  14  
 15              List<Contracts.ParentName> listParent =  new  List<Contracts.ParentName> ();
  16               for  ( int  i =  0 ; i <=  10000 ; i++ )
  17               {
  18                  Contracts.ParentName parentName =  new   Contracts.ParentName()
  19                   {
  20                      Parent =  i.ToString()
  21                   };
  22                   listParent.Add(parentName);
  23               }
  24  
 25              DataContractSerialize<List<Contracts.ParentName>>(listParent,  "  list.xml  " ,  false  );
  26  
 27               //  DataContractSerialize<Contracts.PersonName>(personName, "person.xml", true);  //  保持引用状态
  28               //  DataContractSerialize<Contracts.PersonName>(personName, "person2.xml", false);  //  不保持引用状态 
 29               Console.Read();
  30           }
  31           ///   <summary> 
 32           ///   DataContractSerializer序列化
  33           ///   </summary> 
 34           ///   <typeparam name="T"></typeparam> 
 35           ///   <param name="instance"></param> 
 36           ///   <param name="fileName"></param> 
 37           public   static   void  DataContractSerialize<T>(T instance,  string  fileName,  bool   preserveReference)
  38           {
  39              DataContractSerializer serializer =  new  DataContractSerializer( typeof (T),  null ,  50 ,  false , preserveReference,  null  );
  40               using  (XmlWriter writer =  new   XmlTextWriter(fileName, Encoding.UTF8))
  41               {
  42                   serializer.WriteObject(writer, instance);
  43  
 44               }
  45               Process.Start(fileName);
  46          }

请看代码中的50,表示的就是wcf每次最多处理的对象数,默认值为65536,我们设置为50就是为了出现那么久违的异常信息。这次我们序列化的事一个列表。

在异常信息中有一个属性MaxItemsInObjectGraph,表示的就是处理的最大对象数,如果出现了这个异常信息的话,我们就需要调高这个值。

如何处理才能解决这个异常信息呢?其实有多种方法:

首先第一个就是Servic eBehavior 有一个属性值MaxItemsInObjectGraph,就可以设置大小。

还有就是通过配置文件的方式。

 1      <behaviors>
 2        <serviceBehaviors>
 3          <behavior name= "  metaDataBehavior  " >
 4            <serviceMetadata httpGetEnabled= "  true  " />
 5            <dataContractSerializer maxItemsInObjectGraph= "  65536  " />
 6          </behavior>
 7        </serviceBehaviors>
 8      </behaviors>

在行为Behaviors节点下,有一个dataContractSerializer 可以通过它来设置对象的大小。

知道了如何来调整大小,那么我们应该如何计算对象的个数呢?

  1       [DataContract]
   2       public   class   Order
   3       {
   4           [DataMember]
   5           public   string  UserName {  get ;  set  ; }
   6           [DataMember]
   7           public   string  UserPwd {  get ;  set  ; }
   8       }
   9       public   class   Exec
  10       {
  11           public   void   Execute()
  12           {
  13              List<Order> list =  new  List<Order> ();
  14               for  ( int  i =  0 ; i <  10 ; i++ )
  15               {
  16                  Order order =  new  Order() { UserName= "  userName  "   };
  17                   list.Add(order);
  18               }        
  19          
 20           }
  21      
 22      }

比如说上面的代码,如果我们序列化list对象,那么相当于我们需要处理多少对象呢?

list对象本身算一个,每个order对象算一个,每个order对象的每个属性算一个,就是1+10+20=31 。序列化一个简单的列表就需要处理31个对象。

如果我们处理一个复杂的数据,那么就会更多了,所以一定要计算好,尽量不要超越设定的最大值。

数据契约序列化DataContractserializer 是xmlObjectSerializer的延伸,是简单化的处理。其中也有区别,例如xml序列化是按照元素的出现位置排序,而datacontractserializer是按照字母顺序排序。当然存在order属性的除外。

每天进步一点,一年就会进步一大步,十年就可以成功,君子当自强不息,君子当好好学习,每天进步

 

分类:  Wcf

作者: Leo_wl

    

出处: http://www.cnblogs.com/Leo_wl/

    

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

版权信息

查看更多关于序列化DataContractSerializer的详细内容...

  阅读:39次