Исключение циклической ссылки с сериализацией JSON с MVC3 и EF4 CTP5w

У меня возникают проблемы с циклической ссылкой, когда я пытаюсь сериализовать объект, возвращенный через EF4 CTP5. Я использую первый подход кода и простые poco для моей модели.

Я добавил атрибуты [ScriptIgnore] к любым свойствам, которые предоставляют обратные ссылки на объект, и, что раздражает, кажется, что все работает нормально, если я вручную создаю экземпляры poco, то есть они сериализуются в JSON в порядке, а атрибут scriptignore подтверждается. Однако, когда я пытаюсь сериализовать объект, возвращенный из DAL, я получаю исключение циклической ссылки «Циклическая ссылка была обнаружена при сериализации объекта типа« System.Data.Entity.DynamicProxies.xxxx »»

Я пробовал несколько способов получения данных, но все они застревают с этой ошибкой:

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

Приведенный ниже метод работает немного лучше, поскольку вместо динамического прокси-объекта временного интервала, вызывающего циклическую ссылку, это объект встречи.

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

Любые идеи или решения этой проблемы?

Обновление Я бы предпочел использовать сериализатор из коробки, если это возможно, хотя Json.Net через nuget подходит в качестве альтернативы, я надеюсь, что его также можно использовать, как я предполагал...


person nakchak    schedule 05.01.2011    source источник
comment
Если кому-то нужно автоматизированное (не передовое) решение этой проблемы, не требующее дополнительного кода, ознакомьтесь с этим QA: Не сериализовать ссылки на классы Entity Framework в JSON (библиотека ServiceStack.Text)   -  person nikib3ro    schedule 21.02.2013


Ответы (5)


У меня была аналогичная проблема с службой WCF, размещенной в IIS, и я пытался сериализовать объекты POCO с помощью класса DataContractJsonSerializer. Встроенный сериализатор JSON, похоже, вообще не обрабатывает циклические ссылки. Я смог обойти это, самостоятельно обрабатывая сериализацию с помощью сериализатора JSON.net и просто возвращая строки json. из моих методов. Сериализатор JSON.net имеет возможность игнорировать циклические ссылки, поскольку сам json их не поддерживает.

person JMorgan    schedule 05.01.2011
comment
+1 используйте Newtonsoft для всего, что связано с JSON. Бонус указывает на установку зависимости от него через NuGet, поскольку в OP упоминается использование MVC3. - person Chris Marisic; 05.01.2011

Что бы я ни делал, динамические прокси оставались камнем преткновения, я дошел до того, что удалил все циклические ссылки в своей модели! но проблема осталась.

Я попробовал Json.Net, но возникла та же проблема.

В конце концов я наткнулся на сообщение об использовании пользовательского JavaScriptConverter

http://hellowebapps.com/2010-09-26/производство-json-from-entity-framework-4-0-generated-classes/

Реализовал код и качает вашего дядю все заработало

person nakchak    schedule 06.01.2011
comment
Я обнаружил, что код в этом посте не скомпилировался, и когда я отредактировал его достаточно, чтобы он скомпилировался, он все еще не работал. Не могли бы вы опубликовать здесь свой работающий пользовательский класс JavaScriptConverter? - person codemonkey; 04.08.2011
comment
@TechnicalSmile использует json.net, многое изменилось с тех пор, как я опубликовал этот вопрос, поскольку теперь он является сериализатором json по умолчанию в стеке mvc, также частью проблемы была CTP-версия EF4, которую я использовал в то время, как это было предварительный выпуск. - person nakchak; 04.02.2014

Я решил это, не прибегая к внешнему сериализатору JSON. Короче говоря, я отключил ProxyCreation в конструкторе контекста моего объекта.

Я не уверен, почему это работает, но я разместил дополнительный вопрос здесь.

person trevorc    schedule 21.01.2011
comment
Я не хотел отключать ленивую загрузку, чтобы заставить это работать. Раздражает то, что атрибут ScriptIgnore, похоже, не подхватывается кодом генерации прокси-сервера EF4 CTP5. Поэтому, когда сериализатор пытается сериализовать прокси-объект, он попытается повторить отношения. Эту проблему можно в основном смягчить, используя анонимные объекты для сериализации в JSON, поскольку большинство моих проблем было вызвано попыткой вернуть слишком полный граф объектов. - person nakchak; 03.02.2011

Я использовал следующий ContractResolver. Обратите внимание, что я унаследовал CamelCaseContractPropertyResolver, чтобы получить эту функцию, но вы также можете наследовать непосредственно от 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);
        }
    }
}

Чтобы использовать его, создайте свой сериализатор, а затем задайте для свойства ContractResolver новый экземпляр этого класса:

var ser = JsonSerializer.Create(sJsonSerializerSettings);            
ser.ContractResolver = new ContractResolver(); 
person holmes    schedule 15.11.2011

Я тоже встречал эту проблему. Ответы на эту тему содержат числовые решения. Но самые лучшие решения для разных случаев с объяснением и тем более без пользовательских сериализаций я нашел в статье Hongye Sun - Обработка ссылок цикла в веб-API.

person RredCat    schedule 16.04.2013