A StackOverflowException is thrown when serializing a cyclically dependent ISerializable using ReferenceLoopHandling.Ignore

I have an outdated application that used binary serialization to save data. Now we wanted to use Json.net 4.5 to serialize data without significant changes to existing classes.

Everything worked well until we reached a circular dependent class. Is there any workaround?

Example code shown below

[Serializable] class Department : ISerializable { public Employee Manager { get; set; } public string Name { get; set; } public Department() { } public Department( SerializationInfo info, StreamingContext context ) { Manager = ( Employee )info.GetValue( "Manager", typeof( Employee ) ); Name = ( string )info.GetValue( "Name", typeof( string ) ); } public void GetObjectData( SerializationInfo info, StreamingContext context ) { info.AddValue( "Manager", Manager ); info.AddValue( "Name", Name ); } } [Serializable] class Employee : ISerializable { [NonSerialized] //This does not work [XmlIgnore]//This does not work private Department mDepartment; public Department Department { get { return mDepartment; } set { mDepartment = value; } } public string Name { get; set; } public Employee() { } public Employee( SerializationInfo info, StreamingContext context ) { Department = ( Department )info.GetValue( "Department", typeof( Department ) ); Name = ( string )info.GetValue( "Name", typeof( string ) ); } public void GetObjectData( SerializationInfo info, StreamingContext context ) { info.AddValue( "Department", Department ); info.AddValue( "Name", Name ); } } 

And the test code

 Department department = new Department(); department.Name = "Dept1"; Employee emp1 = new Employee { Name = "Emp1", Department = department }; department.Manager = emp1; Employee emp2 = new Employee() { Name = "Emp2", Department = department }; IList<Employee> employees = new List<Employee>(); employees.Add( emp1 ); employees.Add( emp2 ); var memoryStream = new MemoryStream(); var formatter = new BinaryFormatter(); formatter.Serialize( memoryStream, employees ); memoryStream.Seek( 0, SeekOrigin.Begin ); IList<Employee> deserialisedEmployees = formatter.Deserialize( memoryStream ) as IList<Employee>; //Works nicely JsonSerializerSettings jsonSS= new JsonSerializerSettings(); jsonSS.TypeNameHandling = TypeNameHandling.Objects; jsonSS.TypeNameAssemblyFormat = FormatterAssemblyStyle.Full; jsonSS.Formatting = Formatting.Indented; jsonSS.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; //This is not working!! //jsonSS.ReferenceLoopHandling = ReferenceLoopHandling.Serialize; //This is also not working!! jsonSS.PreserveReferencesHandling = PreserveReferencesHandling.All; string jsonAll = JsonConvert.SerializeObject( employees, jsonSS ); //Throws stackoverflow exception 

Edit1 : The problem was posted by Json ( http://json.codeplex.com/workitem/23668 )

Edit2 : Serialization works fine in version 4.5 of R11, but de-serialization still doesn't work

Edit3 : in fact, serialization itself does not work if the round reference object is not null.

Edit4 . A comment from the Json.net database is that the problem is in the end and closed the problem. But I could not find out what was wrong with my code. I added another question . Thanks to everyone for the answer, the vote ...

+6
source share
2 answers

I think you'll need both ReferenceLoopHandling.Serialize and PreserveReferencesHandling.All to reproduce the behavior of binary serialization. As a result, JSON may not be pretty.

EDIT: I looked deeper into JSON.Net 4.5r10 and found a flaw: JsonSerializerInternalWriter does not check #ShouldWriteReference for links received through ISerializable .

With the foreach in #SerializeISerializable rewritten as shown below, the graph of objects is rounded to the end.

  foreach (SerializationEntry serializationEntry in serializationInfo) { writer.WritePropertyName(serializationEntry.Name); var entryValue = serializationEntry.Value; var valueContract = GetContractSafe(entryValue); if (ShouldWriteReference(entryValue, null, valueContract, null, member)) { WriteReference(writer, entryValue); } else { SerializeValue(writer, entryValue, valueContract, null, null, member); } } 
+5
source

Have you tried this?

 [Serializable] class Employee : ISerializable { [NonSerialized] [XmlIgnore] public Department Department { get; set; } 

NonSerialized Indicates that the field of the serializable class should not be serialized.

XmlIgnore Indicates the Serialize method of XmlSerializer is not to serialize a public field or public read / write property value

0
source

All Articles