13 votes

Exception de référence circulaire avec la sérialisation JSON avec MVC3 et EF4 CTP5w

J'ai des problèmes avec une référence circulaire lorsque j'essaie de sérialiser un objet renvoyé par EF4 CTP5. J'utilise l'approche "code first" et des poco's simples pour mon modèle.

J'ai ajouté des attributs [ScriptIgnore] à toutes les propriétés qui fournissent une référence arrière à un objet et, malheureusement, tout semble fonctionner correctement si j'instancie manuellement les poco's, c'est-à-dire qu'ils se sérialisent bien en JSON et que l'attribut scriptignore est reconnu. Cependant, lorsque j'essaie de sérialiser un objet renvoyé par le DAL, je reçois l'exception de référence circulaire "Une référence circulaire a été détectée lors de la sérialisation d'un objet de type 'System.Data.Entity.DynamicProxies.xxxx'".

J'ai essayé plusieurs façons de récupérer les données, mais elles sont toutes bloquées par cette erreur :

    public JsonResult GetTimeSlot(int id) {
        TimeSlotDao tsDao = new TimeSlotDao();
        TimeSlot ts = tsDao.GetById(id);
        return Json(ts);
    }

La méthode ci-dessous fonctionne un peu mieux car ce n'est pas l'objet proxy dynamique du créneau horaire qui provoque la référence circulaire, mais l'objet rendez-vous.

    public JsonResult GetTimeSlot(int id) {
        TimeSlotDao tsDao = new TimeSlotDao();
            var ts = from t in tsDao.GetQueryable()
                 where t.Id == id
                 select new {t.Id, t.StartTime, t.Available, t.Appointment};
        return Json(ts);
    }

Des idées ou des solutions à ce problème ?

Mise à jour Je préférerais utiliser le sérialiseur prêt à l'emploi si possible, bien que Json.Net via nuget soit une alternative acceptable, j'espère qu'il est possible de l'utiliser comme je l'avais prévu...

4voto

JMorgan Points 555

J'ai eu un problème similaire avec un service WCF hébergé par IIS et en essayant de sérialiser des objets POCO avec la classe DataContractJsonSerializer. Le sérialiseur JSON intégré ne semble pas du tout gérer les références circulaires. J'ai pu contourner le problème en gérant moi-même la sérialisation à l'aide de la classe JSON.net sérialiseur, et je renvoie simplement des chaînes json à partir de mes méthodes. Le sérialiseur JSON.net dispose d'une option permettant d'ignorer les références circulaires, car json lui-même ne les prend pas en charge.

2voto

nakchak Points 348

Peu importe ce que j'ai fait, les proxies dynamiques ont continué à être un point de blocage, je suis allé jusqu'à supprimer toutes les références circulaires dans mon modèle ! mais le problème a persisté.

J'ai essayé Json.Net mais le même problème s'est produit.

Finalement, je suis tombé sur un article concernant l'utilisation d'un JavaScriptConverter personnalisé.

http://hellowebapps.com/2010-09-26/producing-json-from-entity-framework-4-0-generated-classes/

J'ai implémenté le code et tout a fonctionné.

1voto

J'ai résolu ce problème sans avoir à recourir à un sérialiseur JSON externe. Dans un élan de folie, j'ai désactivé ProxyCreation dans le constructeur de mon contexte objet.

Je ne suis pas sûr de la raison pour laquelle cela fonctionne, mais j'ai posté une question de suivi. ici.

1voto

holmes Points 336

J'ai utilisé le ContractResolver suivant. Notez que j'ai hérité de CamelCaseContractPropertyResolver pour obtenir cette fonctionnalité également, mais vous pouvez aussi hériter directement de DefaultContractResolver.

using System;
using System.Collections.Generic;
using System.Reflection;
using Newtonsoft.Json.Serialization;

namespace MyNamespace
{
    /// <summary>
    /// This class enables EntityFramework POCO objects to be serialized. In some cases POCO
    /// objects are subclassed by a proxy which has an additional member _entityWrapper. This
    /// object prevents serialization (circular references and references to non-serializable types).
    /// This removes the _entityWrapper from the list of members to be serialized.
    /// </summary>
    public class ContractResolver : CamelCasePropertyNamesContractResolver
    {
        protected override List<MemberInfo> GetSerializableMembers(Type objectType)
        {
            if (objectType.FullName.StartsWith("System.Data.Entity.DynamicProxies."))
            {
                var members = base.GetSerializableMembers(objectType);
                members.RemoveAll(memberInfo => memberInfo.Name == "_entityWrapper");
                return members;
            }
            return base.GetSerializableMembers(objectType);
        }
    }
}

Pour l'utiliser, créez votre sérialiseur, puis définissez la propriété ContractResolver sur une nouvelle instance de cette classe :

var ser = JsonSerializer.Create(sJsonSerializerSettings);            
ser.ContractResolver = new ContractResolver();

0voto

RredCat Points 1701

J'ai également rencontré ce problème. Les réponses à ce sujet contiennent un certain nombre de solutions. Mais les meilleures solutions pour différents cas avec explication et de plus sans sérialiseurs personnalisés, je les ai trouvées dans l'article de Hongye Sun - Traitement des références de boucles dans l'API Web .

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