Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Circular Reference when using XML Serialization?

Tags:

I am receiving the following exception when trying to serialize an object using XMLSerialization.

A circular reference was detected while serializing an object of type MyObject}

I know the circular reference is because ObjectA can have a childObject of ObjectB and ObjectB's parentObject is ObjectA, however I would like to keep that reference if possible . Is there a way to get this object to serialize with XML Serialization without losing any data during the serialization process? I'm not very familar with serialization so I'm hoping theres some kind of Attribute I could set.

like image 640
Rachel Avatar asked Sep 28 '10 16:09

Rachel


People also ask

What is the correct way of using XML serialization?

XML serialization does not convert methods, indexers, private fields, or read-only properties (except read-only collections). To serialize all an object's fields and properties, both public and private, use the DataContractSerializer instead of XML serialization.

What is the difference between binary serialization and XML serialization?

Xml Serializer serializes only public member of object but Binary Serializer serializes all member whether public or private. In Xml Serialization, some of object state is only saved but in Binary Serialization, entire object state is saved.

What does it mean to serialize XML?

XML serialization is the process of converting XML data from its representation in the XQuery and XPath data model, which is the hierarchical format it has in a Db2® database, to the serialized string format that it has in an application.

What is circular reference exception C#?

Circular reference occurs when two or more interdependent resources cause lock condition. This makes the resource unusable. To handle the problem of circular references in C#, you should use garbage collection.


2 Answers

There are several options depending on serializer type.

If you could use DataContractSerializer or BinaryFormatter then you may use OnSerializedAttribute and set Parent property for your child object to this:

[Serializable] public class Child {     public string Foo { get; set; }      public Parent Parent { get { return parent; } set { parent = value; } }      // We don't want to serialize this property explicitly.     // But we could set it during parent deserialization     [NonSerialized]     private Parent parent; }  [Serializable] public class Parent {     // BinaryFormatter or DataContractSerializer whould call this method     // during deserialization     [OnDeserialized()]     internal void OnSerializedMethod(StreamingContext context)     {         // Setting this as parent property for Child object         Child.Parent = this;     }      public string Boo { get; set; }      public Child Child { get; set; } }  class Program {     static void Main(string[] args)     {         Child c = new Child { Foo = "Foo" };         Parent p = new Parent { Boo = "Boo", Child = c };          using (var stream1 = new MemoryStream())         {             DataContractSerializer serializer = new DataContractSerializer(typeof (Parent));             serializer.WriteObject(stream1, p);             stream1.Position = 0;             var p2 = (Parent)serializer.ReadObject(stream1);              Console.WriteLine(object.ReferenceEquals(p, p2)); //return false             Console.WriteLine(p2.Boo); //Prints "Boo"              //Prints: Is Parent not null: True             Console.WriteLine("Is Parent not null: {0}", p2.Child.Parent != null);         }     }  } 

If you want to use XmlSerializer you should implement IXmlSerializable, use XmlIgnoreAttribute and implemented more or less the same logic in ReadXml method. But in this case you should also implement all Xml serialization logic manually:

[Serializable] public class Child {     public Child()     {     }      public string Foo { get; set; }      [XmlIgnore]     public Parent Parent { get; set; } }  [Serializable] public class Parent {     public Parent()     {     }      #region IXmlSerializable Members      public System.Xml.Schema.XmlSchema GetSchema()     {         throw new NotImplementedException();     }      public void ReadXml(System.Xml.XmlReader reader)     {         //Reading Parent content         //Reading Child         Child.Parent = this;     }      public void WriteXml(System.Xml.XmlWriter writer)     {         //Writing Parent and Child content     }      #endregion      public string Boo { get; set; }      public Child Child { get; set; } } 
like image 80
Sergey Teplyakov Avatar answered Sep 28 '22 02:09

Sergey Teplyakov


If you can use the DataContractSerializer instead of the XMLSerializer then you can use the IsReference property on the DataContract attribute. Enabling this will keep the references, so that they will be recreated upon deserialization.

The DataContractSerializer also serializes to XML, but you have somewhat less control over what the output looks like, that you do with the older XMLSerializer. You can read more about the serializers here: http://www.danrigsby.com/blog/index.php/2008/03/07/xmlserializer-vs-datacontractserializer-serialization-in-wcf/

like image 30
AHM Avatar answered Sep 28 '22 02:09

AHM