Wcf序列化的循环引用问题1

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>
原文地址:https://www.cnblogs.com/tianma3798/p/5482261.html