zoukankan      html  css  js  c++  java
  • 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>
  • 相关阅读:
    Swagger介绍
    mybatis-plus常用操作
    [比赛][蓝桥杯] 第十一届蓝桥杯第二次省赛C++A组
    [题目][蓝桥杯PREV-14] 高僧斗法
    [题目][蓝桥杯PREV] 大合集
    [题目][APIO2009][蓝桥杯ALGO-44] 采油区域
    [题目][蓝桥杯ALGO] 大合集
    [题目][NOIP2001][蓝桥杯ALGO-25] Car 的旅行路线
    [题目][蓝桥杯ALGO-22] 数的划分
    [知识点] 1.5.3 运算符重载
  • 原文地址:https://www.cnblogs.com/tianma3798/p/5482261.html
Copyright © 2011-2022 走看看