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.