1.Wcf数据契约序列化,使用的类DataContractSerializer
默认如果类不指定[DataContract],则序列化类的所有字段,并且在出现循环引用的时候回抛出异常,服务终止
msdn文档说明:https://msdn.microsoft.com/library/system.runtime.serialization.datacontractserializer.aspx
/* * Wcf 数据契约序列化使用“DataContractSerializer”,底层是xml序列化 * 1.如果类上不指定 [DataContract],默认序列化,对象的所有属性(包括null的) * 2.如果类上指定 [DataContract],序列化只检测 属性有 [DataMember] 的 * 3.没有显示指定忽略某字段的方式 */ //创建班级 Grade gradeOne = new Grade() { GradeID = 1, GradeName = "班级1" }; gradeOne.Students = new List<Student>(); //添加班级下的学生 Student stu = new Student(); stu.ID = 1; stu.Name = "张三"; //设置学生所属的班级 /* * 1.注意:如果当前子类的父类对象引用了当前父类对象抛出循环引用异常 * 解决方法1: 对于需要序列化的类显示指定契约标识 [DataContract] * 并且忽略 子类的父类对象, * 也就是 对 Grade 不指定 [DataMember] */ /* * 解决方法2: * 在类的方法标记使用 [DataContract(IsReference = true)] * IsReference:如果使用标准 XML 保留对象引用数据,则为 true;否则为 false */ stu.Grade = gradeOne; gradeOne.Students.Add(stu); DataContractSerializer serializer = new DataContractSerializer(gradeOne.GetType()); string result = null; using (MemoryStream s = new MemoryStream()) { serializer.WriteObject(s, gradeOne); s.Seek(0, SeekOrigin.Begin); using (StreamReader r = new StreamReader(s)) { result = r.ReadToEnd(); } } Console.WriteLine(result);
默认设置(出现异常):
public class Student { public int ID { get; set; } public string Name { get; set; } public Grade Grade { get; set; } } public class Grade { public int GradeID { get; set; } public string GradeName { get; set; } public List<Student> Students { get; set; } }
解决方法1,忽略导致循环引用的属性:
这样的缺点:就是在客户端获取到学生对象,不能直接也得到学生所属的班级对象
[DataContract] public class Student { [DataMember] public int ID { get; set; } [DataMember] public string Name { get; set; } [DataMember] public Grade Grade { get; set; } } [DataContract] public class Grade { [DataMember] public int GradeID { get; set; } [DataMember] public string GradeName { get; set; } [DataMember] public List<Student> Students { get; set; } }
序列化结果:
<?xml version="1.0" encoding="utf-8"?> <Grade xmlns="http://schemas.datacontract.org/2004/07/Test" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"> <GradeID>1</GradeID> <GradeName>班级1</GradeName> <Students> <Student> <Grade i:nil="true"/> <ID>1</ID> <Name>张三</Name> </Student> </Students> </Grade>
解决方法2(推荐),在DataContract上使用IsReference参数,并且设置为true,
互操作引用说明:https://msdn.microsoft.com/zh-cn/library/cc656708(v=vs.110).aspx
IsReferences:如果使用标准 XML 保留对象引用数据,则为 true;否则为 false。
[DataContract(IsReference = true)] public class Student { [DataMember] public int ID { get; set; } [DataMember] public string Name { get; set; } [DataMember] public Grade Grade { get; set; } } [DataContract(IsReference = true)] public class Grade { [DataMember] public int GradeID { get; set; } [DataMember] public string GradeName { get; set; } [DataMember] public List<Student> Students { get; set; } }
或者在初始化对象的时候指定
DataContractSerializer serializer = new DataContractSerializer(typeof(Parent), "Parent", string.Empty, null, int.MaxValue, false, true, null, null);
序列化结果:
<?xml version="1.0" encoding="utf-8"?> <Grade xmlns="http://schemas.datacontract.org/2004/07/Test" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/"
z:Id="i1"> <GradeID>1</GradeID> <GradeName>班级1</GradeName> <Students> <Student z:Id="i2"> <Grade z:Ref="i1"/> <ID>1</ID> <Name>张三</Name> </Student> </Students> </Grade>