182 votes

Une référence circulaire a été détectée lors de la sérialisation d'un objet de type 'SubSonic.Schema .DatabaseColumn'.

J'essaye de faire un simple retour JSON mais j'ai des problèmes J'ai les éléments suivants.

public JsonResult GetEventData()
{
    var data = Event.Find(x => x.ID != 0);
    return Json(data);
}

Je reçois un HTTP 500 avec l'exception indiquée dans le titre de cette question. J'ai également essayé

var data = Event.All().ToList()

Cela a donné le même problème.

S'agit-il d'un bug ou de mon implémentation ?

1 votes

Regarde celui-là. Il existe une solution utilisant le ScriptIgnore attribut. stackoverflow.com/questions/1193857/subsonic-3-0-0-2-structures-tt

0 votes

C'était la meilleure solution pour moi ; j'avais Jeu > Tournoi > Jeu > Tournoi > Jeu, etc. J'ai placé un ScriptIgnore sur la propriété Tournament.Game et cela a bien fonctionné :)

0 votes

Si quelqu'un veut une solution "automatisée" (et non une meilleure pratique) pour ce problème qui ne nécessite pas de code supplémentaire, consultez ce QA : Ne pas sérialiser les références de classe Entity Framework en JSON (bibliothèque ServiceStack.Text)

184voto

Darin Dimitrov Points 528142

Il semble qu'il y ait des références circulaires dans votre hiérarchie d'objets, ce qui n'est pas pris en charge par le sérialiseur JSON. Avez-vous besoin de toutes les colonnes ? Vous pourriez récupérer uniquement les propriétés dont vous avez besoin dans la vue :

return Json(new 
{  
    PropertyINeed1 = data.PropertyINeed1,
    PropertyINeed2 = data.PropertyINeed2
});

Votre objet JSON sera ainsi plus léger et plus facile à comprendre. Si vous avez beaucoup de propriétés, AutoMapper pourrait être utilisé pour automatiquement la correspondance entre les objets DTO et les objets View.

0 votes

Je pense que sélectionner ceux que je veux pourrait fonctionner. Je pense que la référence circulaire est due au fait que dans Event j'ai IQueryable<Category> qui à son tour aura un IQueryable<Event>.

8 votes

Automapper n'est pas une garantie que vous ne rencontrerez pas ce problème. Je suis venu ici pour trouver une réponse et j'utilise actuellement Automapper.

1 votes

Consultez la réponse de @ClayKaboom car elle explique pourquoi cela peut être circulaire.

119voto

ddfnfal Points 76

J'ai eu le même problème et l'ai résolu en using Newtonsoft.Json;

var list = JsonConvert.SerializeObject(model,
    Formatting.None,
    new JsonSerializerSettings() {
        ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
});

return Content(list, "application/json");

3 votes

Ce code en ligne a bien fonctionné pour moi. La même chose dans la configuration globale, comme mentionné par kravits88, ne fonctionne pas pour moi. AUSSI, la signature de la méthode devrait être mise à jour pour retourner ContentResult pour ce code.

8 votes

Cette réponse devrait être considérée comme la meilleure, car elle couvre les cas où vous ne pouvez pas passer des heures à convertir vos objets en d'autres représentations comme dans la réponse marquée comme acceptée.

0 votes

J'ai fait cela mais maintenant j'obtiens une exception de référence nulle pendant la sérialisation et aucune idée de la propriété qui en est la cause.

58voto

ClayKaboom Points 740

Cela se produit en fait parce que les objets complexes sont ce qui fait que l'objet json résultant échoue. Et cela échoue parce que lorsque l'objet est mappé, il mappe les enfants, qui mappent leurs parents, ce qui crée une référence circulaire. Json prendrait un temps infini pour le sérialiser, ce qui évite le problème de l'exception.

Le mappage d'Entity Framework produit également le même comportement, et la solution consiste à écarter toutes les propriétés indésirables.

Pour expliquer la réponse finale, le code entier serait :

public JsonResult getJson()
{
    DataContext db = new DataContext ();

    return this.Json(
           new {
                Result = (from obj in db.Things select new {Id = obj.Id, Name = obj.Name})
               }
           , JsonRequestBehavior.AllowGet
           );
}

Il peut également s'agir de ce qui suit, dans le cas où vous ne voulez pas que les objets à l'intérieur d'un fichier Result propriété :

public JsonResult getJson()
{
    DataContext db = new DataContext ();

    return this.Json(
           (from obj in db.Things select new {Id = obj.Id, Name = obj.Name})
           , JsonRequestBehavior.AllowGet
           );
}

1 votes

+1 pour des choses claires et faciles à comprendre, merci @Clay. J'aime votre explication sur les concepts derrière l'erreur.

7voto

Marc Gravell Points 482669

JSON, comme xml et divers autres formats, est un format de sérialisation basé sur l'arbre. Il ne vous aimera pas si vous avez des références circulaires dans vos objets, comme le serait l'"arbre" :

root B => child A => parent B => child A => parent B => ...

Il y a souvent des moyens de désactiver la navigation le long d'un certain chemin ; par exemple, avec XmlSerializer vous pouvez marquer la propriété parentale comme XmlIgnore . Je ne sais pas si cela est possible avec le sérialiseur json en question, ni si DatabaseColumn a des marqueurs appropriés ( très peu probable, car il faudrait référencer chaque API de sérialisation)

4voto

nilesh Points 139

C'est à cause du nouveau modèle DbContext T4 qui est utilisé pour générer les entités EntityFramework. Afin de pouvoir effectuer le suivi des changements, ce modèle utilise le modèle Proxy, en enveloppant vos jolis POCOs avec eux. Cela pose des problèmes lors de la sérialisation avec le JavaScriptSerializer.

Alors les 2 solutions sont :

  1. Soit vous vous contentez de sérialiser et de renvoyer les propriétés dont vous avez besoin sur le client.
  2. Vous pouvez désactiver la génération automatique de proxies en l'indiquant dans la configuration du contexte.

    context.Configuration.ProxyCreationEnabled = false ;

Très bien expliqué dans l'article ci-dessous.

http://juristr.com/blog/2011/08/javascriptserializer-circular-reference/

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X