1

Closed

self referencing loop exception with [JsonObject(IsReference = true)]

description

During some tests with RavenDb I receive a JsonSerializationException during the serialization of my object. The error is:
 
{"Self referencing loop detected for type
'System.Collections.Generic.List`1[RavenDbTest.Category]'."}
 
The class that I try to save is the following:
 
[JsonObject( IsReference = true )]
public class Category
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public Category Parent { get; set; }
    public IList<Category> Children { get; set; }
 
    public Category()
        : base()
    {
        Children = new List<Category>();
    }
 
    public void Add( Category category )
    {
        category.Parent = this;
        Children.Add( category );
    }
 
    public override Boolean Equals( Object obj )
    {
        return true;
    }
}
 
 
I have added the JsonObject attribute in order to avoid self reference
error. The problem arise when I override the Equals method and
returing always true.
 
Of course this is a unreal implementation, but I have a project where
the same error arise.
Closed May 27, 2012 at 7:37 AM by JamesNK
Using reference doesn't work for structs. Also it can't change because it would be a breaking change. You'll either have change Equals or set references to be serialized.

comments

aparata wrote May 22, 2012 at 2:10 PM

After a little of digging in the code seems that the problem is in JsonSerializerInternalWriter at row 226. The code is:


if (_serializeStack.IndexOf(value) != -1)
{ ... }

if the 'value' object override the Equals method in a not conventional way (as in my example) the condition may assume a true value when instead it should be false.

A possible solution can be to substitute the code with something similar to the following:

if (_serializeStack.Any( o => Object.ReferenceEquals( o, value) ) )
{ ... }

aparata wrote May 27, 2012 at 10:51 AM

Thanks James for the answer.

Just one last question,

unfortunately I cannot change the entities in the domain.

I understand that with Struct value my change doesn't work, but do you think is acceptable to have in our code base (of course with a more elegant code) a solution like this?

if (value.GetType().IsValueType ? _serializeStack.IndexOf(value) != -1 : _serializeStack.Any( o => Object.ReferenceEquals( o, value) ))


What kind of problems can we have (you have talking about a breaking change)?

JamesNK wrote May 27, 2012 at 9:29 PM

Getting the type like that will hurt performance. That check is made for every deserialized object.

If you want reference loops serialized then set them to serialize instead of erroring.