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]».

Développeur passionné
la source
2
duplication possible de l' erreur JSON.NET Boucle d'auto-référencement détectée pour le type
Chris Moschini
Pourriez-vous s'il vous plaît marquer ma réponse comme correcte si elle l'est? @Kovu
Muhammad Omar ElShourbagy
Possible duplication de la boucle d'auto-référencement du framework Entity détectée
Michael Freidgeim

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

Muhammad Omar ElShourbagy
la source
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

smocker
la source
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
    );
andreisrob
la source
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

Ddagsan
la source
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

Cyrus
la source
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; }
}
Samet Sunman
la source
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;
                });
krishnan2784
la source
2

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

services.AddControllers().AddNewtonsoftJson(opt=>{
            opt.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
        });
Karim Tingdis
la source
1

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

user3824027
la source
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
            }));
Angélica Tovar
la source