ef4 причиной Циркулярная ссылка в веб-сервисе - PullRequest
4 голосов
/ 23 апреля 2011

У меня есть объект Reason:

public class Reason
{
    public virtual long Id { get; set; }
    public virtual string Name { get; set; }
    public virtual Company Company {get;set;}
}

Я использую Entity Framework 4, и Company является свойством навигации для Company.
Я также использую веб-сервисы для возврата данных клиенту.
У меня есть веб-метод, который возвращает Причины:

  [WebMethod]
    public Reason[] GetCallReasons()
    {
        IReasonRepository rep =
            ObjectFactory.GetInstance<IReasonRepository>();
        return rep.GetReasonsList().ToArray();
    }

Из-за ef4 я получаю следующее исключение для выполнения веб-метода:

A circular reference was detected while serializing an object of type 'System.Data.Entity.DynamicProxies.Reason_24A0E4BBE02EE6BC2CF30BB56CFCB670C7D9D96D03D40AF4D174B89C9D3C5537'

Проблема возникает, потому что ef4 добавляет свойство, котороене может быть сериализовано: Image of the watch panel on rep.GetReasonsList().ToArray()

Чтобы решить эту проблему и устранить ошибку, я могу отключить свойство навигации, не делая его виртуальным или удаляя свойство навигации.Но я использую его и хочу использовать функцию отложенной загрузки.

Я также могу написать специальный сериализатор для Reason, но у меня есть много классов, которые я использовал в своих веб-сервисах, и написать сериализатор для всех них:много работы.

Как я могу решить это исключение? ..

Ответы [ 3 ]

11 голосов
/ 23 апреля 2011

Существует несколько решений для вашей проблемы, и они действительно зависят от типа службы, которую вы используете, и от типа сериализации:

  • Чистый подход использует DTO (объекты передачи данных) в качестве@ Микаэль уже предложил.DTO - это особый объект, который передает именно то, что вам нужно, и ничего более.Вы можете просто создать DTO, чтобы они не содержали циклические ссылки, и использовать AutoMapper для отображения между сущностями и DTO и наоборот.+1 за @Mikael, потому что он первым упомянул это.

Все остальные подходы основаны на сериализации твиков, как предложил @Haz:

  • WCF и DataContractSerializer: явно пометить ваши сущности с DataContract[IsReference=true] и все свойства с [DataMember] атрибутами.Это позволит вам использовать циклические ссылки.Если вы используете шаблон T4 для генерации сущностей, вы должны изменить его, чтобы добавить эти атрибуты для вас.
  • WCF и DataContractSerializer: неявная сериализация.Пометьте одно из связанных свойств навигации атрибутом [IgnoreDataMember], чтобы свойство не сериализовалось.
  • XmlSerializer: пометьте одно для связанных свойств навигации атрибутом [XmlIgnore]
  • Другие сериализации: отметьте односвязанных свойств навигации с [NonSerialized] (+1 для Haz, он первым упомянул об этом) для обычной сериализации или [ScriptIgnore] для некоторой связанной с JSON сериализации.
8 голосов
/ 23 апреля 2011

Я обычно пишу определенные классы для веб-сервиса. Несмотря на то, что это дополнительная работа, она имеет преимущество в том, что веб-сервис становится более надежным, поскольку небольшие изменения в ваших сущностях не останутся безнаказанными и будут молча терпеть неудачу на стороне потребителя / JavaScript. Например, если я изменю имя свойства.

Есть несколько вещей, которые вы можете сделать, чтобы уменьшить объем работы, и один из них - использовать AutoMapper, который может автоматически сопоставлять объекты.

4 голосов
/ 23 апреля 2011

Вы не предоставили определение для класса своей компании .... Но я предполагаю, что у вас есть коллекция Reason в качестве свойства.

Ленивая загрузка в среде SOA действительно не работает,Вы не можете иметь неограниченную ленивую навигацию по сериализованному классу, после того как вы покинете веб-метод, у вас не будет возможности перезвонить исходному тексту данных от потребителя веб-метода для поиска подходящих объектов ... так что сериализатор попытается посетить все свойства,включая ленивые свойства во время сериализации.

Необходимо отключить сериализацию для одной части циклической ссылки, либо для коллекции Reason в классе Company, либо для Company в классе Reason.

Вы можете использовать атрибут NotSerialized, чтобы отключить сериализацию определенного поля.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...