Как вы «действительно» сериализуете объекты круговой ссылки с помощью 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;
для всех свойств навигации, чтобы разорвать круговые ссылки? Потому что это тоже не кажется правильным.