Boucle d'auto-référencement JSON.Net détectée


111

J'ai une base de données mssql pour mon site Web dans 4 tables.

Quand j'utilise ceci:

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

Le code entraîne l'erreur suivante:

Newtonsoft.Json.JsonSerializationException: Boucle d'auto-référencement détectée pour la propriété 'CyberUser' de type 'DAL.CyberUser'. Chemin «[0] .EventRegistrations [0] .CyberUser.UserLogs [0]».



Pourriez-vous s'il vous plaît marquer ma réponse comme correcte si elle l'est? @Kovu
Muhammad Omar ElShourbagy

Réponses:


212

J'ai juste eu le même problème avec les collections Parent / Child et j'ai trouvé ce post qui a résolu mon cas. Je voulais uniquement afficher la liste des éléments de la collection parent et je n'avais besoin d'aucune des données enfants, j'ai donc utilisé ce qui suit et cela a bien fonctionné:

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

Erreur JSON.NET Boucle d'auto-référencement détectée pour le type

il fait également référence à la page codeplex Json.NET à l'adresse:

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

Documentation: Paramètre ReferenceLoopHandling


2
Selon le cas, vous pouvez également utiliser PreserveReferencesHandling = PreserveReferencesHandling.Objects;comme expliqué ici: résoudre-auto-referencing-loop-issue-when-using-newtonsoft-json
Dimitri Troncquo

Dans WebAPI OData v4, j'ai trouvé que certains types de données nécessitaient à la fois ReferenceLoopHandling.Ignore et PreserveReferencesHandling.Objects
Chris Schaller

1
Chante Allelluiah Merci beaucoup, seul un vote par 1 n'est pas suffisant
JP Chapleau

42

Le correctif est d'ignorer les références de boucle et de ne pas les sérialiser. Ce comportement est spécifié dans JsonSerializerSettings.

SeulJsonConvert avec une surcharge:

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

Si vous souhaitez en faire le comportement par défaut, ajoutez un paramètre global avec du code Application_Start()dans Global.asax.cs:

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

Référence: https://github.com/JamesNK/Newtonsoft.Json/issues/78


3
La sérialisation avec cela prend beaucoup de temps pour moi
Daniel

Cela ne semble pas fonctionner lorsque l'objet avec des boucles circulaires sont des POCO de modèle NHibernate (dans ce cas, la sérialisation récupère une tonne de déchets, ou parfois expire).
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 = neutre, PublicKeyToken = 7cec85d7bea7798e "," Name ": null," HasDefaultValue ": true," DefaultValue ": null," RawDefaultValue ": null," MetadataToken ": 134217728," Attributes ": 0," Position ": - 1, "IsIn": false, "IsLcid": false ,. ... etc.

37

Si vous utilisez ASP.NET Core MVC, ajoutez ceci à la méthode ConfigureServices de votre fichier startup.cs:

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

2
J'ai confirmé que cette solution fonctionne également avec WebAPI EntityFramework Core 2.0
cesar-moya

13

Cela peut vous aider.

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
C'est la meilleure façon de l'aborder si vous utilisez également des méthodes asynchrones. Cela peut être une vraie douleur, mais cela résout beaucoup de problèmes que vous auriez autrement (y compris celui-ci) et peut également être beaucoup plus performant car vous ne demandez que ce que vous allez utiliser.
Josh McKearin le

Dans votre xyz.edmx, ouvrez le fichier xyz.Context.vb qui sera masqué par défaut. Cela aura codePublic Sub New () Mybase.New ("name = EntityConName") End Sub code. Maintenant, avant End Sub, ajoutez codeMe.Configuration.LazyLoadingEnabled = False Me.Configuration.ProxyCreationEnabled = False code Cela éliminera l'erreur 'Self referencing loop' dans votre sortie json de webapi.
Venkat

J'ai trouvé que cela ne fonctionnait pas pour moi. J'ai utilisé AsNoTracking () et cela l'a corrigé. Peut-être aider quelqu'un d'autre
scottsanpedro

@scottsanpedro c'était mieux si nous pouvions voir votre code.
ddagsan le

6

Vous devez définir des références d'objet de conservation:

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

Ensuite, appelez votre requête var q = (from a in db.Events where a.Active select a).ToList();comme

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

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


4

Ajoutez «[JsonIgnore]» à votre classe de modèle

{
  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

J'utilise Dot.Net Core 3.1 et j'ai recherché

"Newtonsoft.Json.JsonSerializationException: boucle d'auto-référencement détectée pour la propriété"

J'ajoute ceci à cette question, car ce sera une référence facile. Vous devez utiliser ce qui suit dans le fichier Startup.cs:

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

2

pour asp.net core 3.1.3 cela a fonctionné pour moi

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

1

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


6
Bien que ce code puisse répondre à la question, fournir un contexte supplémentaire concernant la raison et / ou la manière dont ce code répond à la question améliore sa valeur à long terme.
Alex Riabov

1

Parfois, vous avez des boucles parce que votre classe de type a des références à d'autres classes et que les classes ont des références à votre classe de type, vous devez donc sélectionner les paramètres dont vous avez besoin exactement dans la chaîne json, comme ce code.

List<ROficina> oficinas = new List<ROficina>();
oficinas = /*list content*/;
var x = JsonConvert.SerializeObject(oficinas.Select(o => new
            {
                o.IdOficina,
                o.Nombre
            }));
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.