Rilevato loop autoreferenziale JSON.Net


111

Ho un database mssql per il mio sito web all'interno di 4 tabelle.

Quando lo uso:

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());
    }
}

Il codice genera il seguente errore:

Newtonsoft.Json.JsonSerializationException: loop autoreferenziale rilevato per la proprietà "CyberUser" con tipo "DAL.CyberUser". Percorso "[0] .EventRegistrations [0] .CyberUser.UserLogs [0]".



Si prega di contrassegnare la mia risposta come corretta se lo è? @Kovu
Muhammad Omar ElShourbagy

Risposte:


212

Ho appena avuto lo stesso problema con le raccolte Genitore / Figlio e ho trovato quel post che ha risolto il mio caso. Volevo solo mostrare l'elenco degli elementi della raccolta genitore e non avevo bisogno di nessuno dei dati figlio, quindi ho usato quanto segue e ha funzionato bene:

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

Errore JSON.NET Ciclo di riferimento automatico rilevato per il tipo

fa riferimento anche alla pagina codeplex di Json.NET all'indirizzo:

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

Documentazione: impostazione ReferenceLoopHandling


2
A seconda del caso potresti anche usare PreserveReferencesHandling = PreserveReferencesHandling.Objects;come spiegato qui: risolvere-self-referencing-loop-issue-when-using-newtonsoft-json
Dimitri Troncquo

In WebAPI OData v4, ho scoperto che alcuni tipi di dati richiedevano sia ReferenceLoopHandling.Ignore che PreserveReferencesHandling.Objects
Chris Schaller

1
Canta Allelluiah Grazie mille solo il voto di 1 non è sufficiente
JP Chapleau

42

La soluzione consiste nell'ignorare i riferimenti al ciclo e non nel serializzarli. Questo comportamento è specificato inJsonSerializerSettings .

singolo JsonConvert con un sovraccarico:

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

Se desideri impostare questo comportamento predefinito, aggiungi un'impostazione globale con il codice in formatoApplication_Start() in Global.asax.cs:

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

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


3
La serializzazione con questo richiede molto tempo per me
daniel

Questo non sembra funzionare quando gli oggetti con loop circolari sono POCO del modello NHibernate (in tal caso la serializzazione recupera una tonnellata di spazzatura, o talvolta si verifica semplicemente il timeout).
Fernando Gonzalez Sanchez

"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 ,. ... eccetera.

37

Se si utilizza ASP.NET Core MVC, aggiungerlo al metodo ConfigureServices del file startup.cs:

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

2
Ho confermato che questa soluzione funziona anche con WebAPI EntityFramework Core 2.0
cesar-moya

13

Questo potrebbe aiutarti.

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
Questo è il modo migliore per affrontarlo se stai usando anche metodi asincroni. Può essere un vero problema, ma risolve molti problemi che avresti altrimenti (incluso questo) e può anche essere molto più performante poiché stai solo chiedendo ciò che utilizzerai.
Josh McKearin

Nel tuo xyz.edmx, apri il file xyz.Context.vb che sarà nascosto per impostazione predefinita. Ciò avrà codePublic Sub New () Mybase.New ("name = EntityConName") End Sub code. Ora prima di End Sub aggiungi codeMe.Configuration.LazyLoadingEnabled = False Me.Configuration.ProxyCreationEnabled = False code Questo eliminerà l' errore "Self referencing loop" nell'output json di webapi.
Venkat

Ho scoperto che questo non ha funzionato per me. Ho usato AsNoTracking () e l'ho risolto. Forse aiutare qualcun altro
scottsanpedro

@scottsanpedro sarebbe stato meglio se potessimo vedere il tuo codice.
ddagsan

6

È necessario impostare Preserving Object References:

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

Quindi chiama la tua query var q = (from a in db.Events where a.Active select a).ToList();come

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

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


4

Aggiungi "[JsonIgnore]" alla tua classe modello

{
  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; }
}

3

Sto usando Dot.Net Core 3.1 e ho cercato

"Newtonsoft.Json.JsonSerializationException: loop autoreferenziale rilevato per la proprietà"

Aggiungo questo a questa domanda, poiché sarà un facile riferimento. È necessario utilizzare quanto segue nel file Startup.cs:

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

2

per asp.net core 3.1.3 questo ha funzionato per me

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

1

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


6
Sebbene questo codice possa rispondere alla domanda, fornire un contesto aggiuntivo sul perché e / o come questo codice risponde alla domanda ne migliora il valore a lungo termine.
Alex Riabov

1

A volte hai dei loop perché la tua classe di tipo ha riferimenti ad altre classi e che le classi hanno riferimenti alla tua classe di tipo, quindi devi selezionare i parametri di cui hai bisogno esattamente nella stringa json, come questo codice.

List<ROficina> oficinas = new List<ROficina>();
oficinas = /*list content*/;
var x = JsonConvert.SerializeObject(oficinas.Select(o => new
            {
                o.IdOficina,
                o.Nombre
            }));
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.