214

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

13 Answers 13

369

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

6
  • In WebAPI OData v4, I found that some types of data required both the ReferenceLoopHandling.Ignore and PreserveReferencesHandling.Objects Jun 15, 2018 at 5:50
  • 1
    Sings Allelluiah Thanks so much only up-voting by 1 is not sufficient Jul 9, 2018 at 12:56
  • 1
    Worked for me for Entity Framework Core on Blazor Server. Mar 4, 2021 at 2:46
  • Thanks! For my project, I've decided to include this as configuration in my startup.cs.
    – Medismal
    Apr 26, 2021 at 9:13
  • 2
    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). Jun 30, 2021 at 15:43
56

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
  • 4
    Serialization with this takes a very long time for me
    – daniel
    Jan 28, 2015 at 22:55
  • 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). Sep 8, 2018 at 0:08
  • "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. Sep 8, 2018 at 0:09
  • 1
    Watch out... if the references are truly circular, using ReferenceLoopHandling.Ignore can cause a stack overflow.
    – Gyromite
    Feb 9, 2022 at 15:27
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
  • 2
    I've confirmed this solution also works with WebAPI EntityFramework Core 2.0
    – cesar-moya
    May 28, 2018 at 19:45
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
  • 4
    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. Jun 29, 2015 at 6:09
  • 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.
    – Venkat
    May 14, 2017 at 19:38
  • I found this didn't work for me. I used AsNoTracking() and it fixed it. Maybe help someone else Feb 20, 2020 at 12:24
  • @scottsanpedro it was better if we could see your code.
    – ddagsan
    Feb 21, 2020 at 13:00
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

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
  • 1
    Worked for me for Entity Framework Core on Blazor Server. – David Jones just now Edit Delete Mar 4, 2021 at 2:47
7

for asp.net core 3.1.3 this worked for me

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

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; }
}
0
3

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.

1
  • 1
    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. Nov 28, 2023 at 14:01
2

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

1
  • 8
    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. Dec 12, 2018 at 9:11
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);
            }
        }
    }
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));
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
            }));

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.