224

I have a mssql database for my website within 4 tables.

When I use this:

public static string GetAllEventsForJSON()
{
    using (CyberDBDataContext db = new CyberDBDataContext())
    {
        return JsonConvert.SerializeObject((from a in db.Events where a.Active select a).ToList(), new JavaScriptDateTimeConverter());
    }
}

The code results in the following error:

Newtonsoft.Json.JsonSerializationException: Self referencing loop detected for property 'CyberUser' with type 'DAL.CyberUser'. Path '[0].EventRegistrations[0].CyberUser.UserLogs[0]'.

3

14 Answers 14

388

I just had the same problem with Parent/Child collections and found that post which has solved my case. I Only wanted to show the List of parent collection items and didn't need any of the child data, therefore i used the following and it worked fine:

JsonConvert.SerializeObject(ResultGroups, Formatting.None,
                        new JsonSerializerSettings()
                        { 
                            ReferenceLoopHandling = ReferenceLoopHandling.Ignore
                        });

JSON.NET Error Self referencing loop detected for type

it also referes to the Json.NET codeplex page at:

http://json.codeplex.com/discussions/272371

Documentation: ReferenceLoopHandling setting

Sign up to request clarification or add additional context in comments.

6 Comments

In WebAPI OData v4, I found that some types of data required both the ReferenceLoopHandling.Ignore and PreserveReferencesHandling.Objects
Sings Allelluiah Thanks so much only up-voting by 1 is not sufficient
Worked for me for Entity Framework Core on Blazor Server.
Thanks! For my project, I've decided to include this as configuration in my startup.cs.
Even using the "ignore" setting newtonsoft seems to partially serialize the self referencing. In my code, it seems the serialized data is about 80x bigger than the real data (when serialized).
|
58

The fix is to ignore loop references and not to serialize them. This behaviour is specified in JsonSerializerSettings.

Single JsonConvert with an overload:

JsonConvert.SerializeObject((from a in db.Events where a.Active select a).ToList(), Formatting.Indented,
    new JsonSerializerSettings() {
        ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
    }
);

If you'd like to make this the default behaviour, add a Global Setting with code in Application_Start() in Global.asax.cs:

JsonConvert.DefaultSettings = () => new JsonSerializerSettings {
     Formatting = Newtonsoft.Json.Formatting.Indented,
     ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
};

Reference: https://github.com/JamesNK/Newtonsoft.Json/issues/78

4 Comments

Serialization with this takes a very long time for me
This doesn't seem to work when the object with circular loops are NHibernate model POCOs (in that case the serialization retrieves a ton of garbage, or sometimes just times out).
"IsSecuritySafeCritical":false,"IsSecurityTransparent":false, "MethodHandle":{"Value":{"value":140716810003120}},"Attributes":150,"CallingConvention":1, "ReturnType":"System.Void, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e", "ReturnTypeCustomAttributes":{"ParameterType":"System.Void, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e","Name":null, "HasDefaultValue":true,"DefaultValue":null,"RawDefaultValue":null,"MetadataToken":134217728,"Attributes":0,"Position":-1,"IsIn":false,"IsLcid":false,. ... etc.
Watch out... if the references are truly circular, using ReferenceLoopHandling.Ignore can cause a stack overflow.
46

If using ASP.NET Core MVC, add this to the ConfigureServices method of your startup.cs file:

services.AddMvc()
    .AddJsonOptions(
        options => options.SerializerSettings.ReferenceLoopHandling =            
        Newtonsoft.Json.ReferenceLoopHandling.Ignore
    );

1 Comment

I've confirmed this solution also works with WebAPI EntityFramework Core 2.0
13

This may help you.

public MyContext() : base("name=MyContext") 
{ 
    Database.SetInitializer(new MyContextDataInitializer()); 
    this.Configuration.LazyLoadingEnabled = false; 
    this.Configuration.ProxyCreationEnabled = false; 
} 

http://code.msdn.microsoft.com/Loop-Reference-handling-in-caaffaf7

4 Comments

This is the best way to approach it if you're also using async methods. It can be a real pain, but it solves a lot of issues you would have otherwise (including this one) and also can be much more performant as you're only querying what you will use.
In your xyz.edmx, open the xyz.Context.vb file which will be hidden by default. This will have code Public Sub New() Mybase.New("name=EntityConName") End Sub code. Now before End Sub add code Me.Configuration.LazyLoadingEnabled = False Me.Configuration.ProxyCreationEnabled = False code That will get rid of 'Self referencing loop' error in your json output from webapi.
I found this didn't work for me. I used AsNoTracking() and it fixed it. Maybe help someone else
@scottsanpedro it was better if we could see your code.
10

You must set Preserving Object References:

var jsonSerializerSettings = new JsonSerializerSettings
{
    PreserveReferencesHandling = PreserveReferencesHandling.Objects
};

Then call your query var q = (from a in db.Events where a.Active select a).ToList(); like

string jsonStr = Newtonsoft.Json.JsonConvert.SerializeObject(q, jsonSerializerSettings);

See: https://www.newtonsoft.com/json/help/html/PreserveObjectReferences.htm

Comments

10

I am using Dot.Net Core 3.1 and did an search for

"Newtonsoft.Json.JsonSerializationException: Self referencing loop detected for property "

I am adding this to this question, as it will be an easy reference. You should use the following in the Startup.cs file:

 services.AddControllers()
                .AddNewtonsoftJson(options =>
                {
                    // Use the default property (Pascal) casing
                    options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
                    options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
                });

1 Comment

Worked for me for Entity Framework Core on Blazor Server. – David Jones just now Edit Delete
7

Add "[JsonIgnore]" to your model class

{
  public Customer()
  {
    Orders = new Collection<Order>();
  }

public int Id { get; set; }
public string Name { get; set; }
public string Surname { get; set; }

[JsonIgnore]
public ICollection<Order> Orders { get; set; }
}

Comments

7

for asp.net core 3.1.3 this worked for me

services.AddControllers().AddNewtonsoftJson(opt=>{
            opt.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
        });

Comments

5

Make sure you aren't accidentally serializing a Task<T>

You can get this error if you forget to await an asynchronous method whose return value you intended to serialize.

    public async Task<JsonResult> GetTaxTable([FromServices] TaxService taxService)
    {
        var taxTable = /* await */ taxService.GetTaxTable();
        return new JsonResult(taxTable);
    }

In this example I had forgotten to await the GetTaxTable async method. So I inadvertently ended up passing a Task to the JsonResult constructor - and a Task isn't serializable. While it may at first look like everything blew up on you - the simple solution is to add await.

2 Comments

This was the answer for me - I was testing my API which makes a call to another API (which was returning vastly more data than I needed). I'd added the async/await to the 3rd party API call, but not to my own. I was getting Self Referencing Loop error and debugging reported an invalid token (start of an array, but the json was verified as valid). I tried a custom serialiser/deserialiser for the object array which didn't work. Everything worked as expected on adding the async/await to my API call.
That was my case too.
2

JsonConvert.SerializeObject(ObjectName, new JsonSerializerSettings(){ PreserveReferencesHandling = PreserveReferencesHandling.Objects, Formatting = Formatting.Indented });

1 Comment

While this code may answer the question, providing additional context regarding why and/or how this code answers the question improves its long-term value.
2

The JsonSerializer instance can be configured to ignore reference loops. Like in the following, this function allows to save a file with the content of the json serialized object:

    public static void SaveJson<T>(this T obj, string FileName)
    {
   
       JsonSerializer serializer = new JsonSerializer();
        serializer.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
        using (StreamWriter sw = new StreamWriter(FileName))
        {
            using (JsonWriter writer = new JsonTextWriter(sw))
            {
                writer.Formatting = Formatting.Indented;
                serializer.Serialize(writer, obj);
            }
        }
    }

Comments

2

If you are like me and were previously calling SerializeObject with a converter, you will need to remove the converter parameter and add it to your config... Like so:

var isoConvert = new IsoDateTimeConverter();
isoConvert.DateTimeFormat = _dateFormat;
List<JsonConverter> converters = new List<JsonConverter>();
converters.Add(isoConvert);
JsonSerializerSettings settings = new JsonSerializerSettings()
{
    PreserveReferencesHandling = PreserveReferencesHandling.Objects,
    ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
    Converters = converters
};

// Old Code:
//response.Write(JsonConvert.SerializeObject(Data, isoConvert);
response.Write(JsonConvert.SerializeObject(Data, settings));

Comments

1

Sometimes you have loops becouse your type class have references to other classes and that classes have references to your type class, thus you have to select the parameters that you need exactly in the json string, like this code.

List<ROficina> oficinas = new List<ROficina>();
oficinas = /*list content*/;
var x = JsonConvert.SerializeObject(oficinas.Select(o => new
            {
                o.IdOficina,
                o.Nombre
            }));

Comments

0

JsonIgnoreAttribute attribute allows you to control which properties of your class get serialized into JSON format. By applying [JsonIgnore] directly above a property declaration, you instruct the serializer to skip that property during the process.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.