Как вы «действительно» сериализуете объекты круговой ссылки с помощью Newtonsoft.Json?

У меня проблема с получением правильной сериализации данных с моего контроллера ASP.NET Web API с использованием Newtonsoft.Json.

Вот что ясчитать происходит - пожалуйста, поправьте меня, если я ошибаюсь. При определенных обстоятельствах (в частности, когда в данных отсутствуют циклические ссылки) все работает так, как вы и ожидаете - список заполненных объектов сериализуется и возвращается. Если я введу данные, которые вызывают круговую ссылку в модели (описано ниже, и даже сPreserveReferencesHandling.Objects set) только элементы списка, ведущие к первому объекту с циклической ссылкой, сериализуются так, чтобы клиент мог «работать» с ними. «Элементами, ведущими к», могут быть любые элементы в данных, если они упорядочены по-разному перед отправкой данных в сериализатор, но по крайней мере один из них будет сериализован так, чтобы клиент мог «работать». Пустые объекты в конечном итоге сериализуются как ссылки Newtonsoft ({$ref:X}).

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

В моем global.asax:

var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;

Вот основной запрос, который я делаю с использованием Entity Framework (отложенная загрузка отключена, поэтому здесь нет прокси-классов):

[HttpGet]
[Route("starting")]
public IEnumerable<Balance> GetStartingBalances()
{
   using (MyContext db = new MyContext())
   {
       var data = db.Balances
        .Include(x => x.Source)
        .Include(x => x.Place)
        .ToList()
       return data;
    }
}

Все идет нормально,data населён.

Если нет циркулярных ссылок, жизнь велика. Тем не менее, как только есть 2Balance лица с одинаковымиSource или жеPlaceзатем сериализация превращается позжеBalance объекты самого верхнего списка, который я возвращаю в ссылки Newtonsoft вместо их полноценных объектов, потому что они уже были сериализованы вBalances собственностьSource или жеPlace объекты):

[{"$id":"1","BalanceID":4,"SourceID":2,"PlaceID":2 ...Omitted for clarity...},{"$ref":"4"}]

Проблема в том, что клиент не знает, что делать с{$ref:4} хотя мы, люди, понимаем, что происходит. В моем случае это означает, что я не могу использовать AngularJS дляng-repeat по всему моему списку весов с этим JSON, потому что они не все верныBalance объекты сBalance свойство связывать. Я уверен, что есть множество других вариантов использования, которые будут иметь такую ​​же проблему.

Я не могу выключитьjson.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects потому что многое другое сломалось бы (что хорошо задокументировано в 100 других вопросах здесь и в других местах).

Есть ли лучший обходной путь для этого помимо прохождения сущностей в контроллере Web API и выполнения

Balance.Source.Balances = null;

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

Ответы на вопрос(1)

Ваш ответ на вопрос