У меня возникла проблема с получением некоторых данных, упорядоченных правильно, с моего контроллера веб-API ASP.NET с использованием Newtonsoft.Json.
Вот что, я думаю, происходит - пожалуйста, поправьте меня, если я ошибаюсь. При определенных обстоятельствах (особенно когда в данных нет каких-либо циклических ссылок) все работает так, как вы ожидали, - список заполненных объектов становится сериализованным и возвращенным. Если я введу данные, которые приводят к циклической ссылке в модели (описанной ниже и даже с установкой PreserveReferencesHandling.Objects
), только элементы списка, ведущие к первому объекту с циклической ссылкой, получают сериализацию таким образом, что клиент может "работать с". "Элементы, ведущие к", могут быть любыми элементами в данных, если они заказываются по-разному, прежде чем отправлять вещи в сериализатор, но по крайней мере один будет сериализован таким образом, чтобы клиент мог "работать с". Пустые объекты в конечном итоге сериализуются как ссылки Newtonsoft ({$ref:X}
).
Например, если у меня есть модель EF, полная свойств навигации, которая выглядит так:
В моем global.asax:
var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
Здесь основной запрос, который я использую с помощью Entity Framework (lazy-load выключен, поэтому здесь нет прокси-классов):
[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
заселен.
Если нет круглых ссылок, жизнь велика. Однако, как только есть 2 Balance
сущности с теми же 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, потому что они не все true Balance
объекты с атрибутом Balance
для привязки. Я уверен, что есть много других прецедентов, которые будут иметь одинаковую проблему.
Я не могу отключить json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects
, потому что много других вещей сломается (что хорошо описано в 100 других вопросах здесь и в других местах).
Есть ли лучший способ обхода этого решения, кроме как просматривать объекты в контроллере Web API и делать
Balance.Source.Balances = null;
всем свойствам навигации, чтобы разбить круговые ссылки? Потому что это тоже не так.