【发布时间】:2014-12-13 14:39:32
【问题描述】:
我在使用 Newtonsoft.Json 从我的 ASP.NET Web API 控制器正确序列化一些数据时遇到问题。
这就是我认为正在发生的事情 - 如果我错了,请纠正我。在某些情况下(特别是当数据中没有任何循环引用时)一切都会像您期望的那样工作 - 填充对象的列表被序列化并返回。如果我在模型中引入导致循环引用的数据(如下所述,即使设置了PreserveReferencesHandling.Objects),只有指向具有循环引用的第一个对象的列表元素会以客户端可以“一起工作”。如果在将内容发送到序列化程序之前以不同的方式排序,则“导致的元素”可以是数据中的任何元素,但至少有一个元素将以客户端可以“使用”的方式进行序列化。空对象最终被序列化为 Newtonsoft 引用 ({$ref:X})。
例如,如果我有一个包含如下导航属性的 EF 模型:
在我的 global.asax 中:
var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
这是我使用实体框架执行的基本查询(延迟加载已关闭,因此这里没有任何代理类):
[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 个具有相同 Source 或 Place 的 Balance 实体,那么序列化就会将我返回到 Newtonsoft 引用而不是它们的最顶层列表的后面的 Balance 对象成熟的对象,因为它们已经在Source 或Place 对象的Balances 属性中序列化:
[{"$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;
要打破循环引用的所有导航属性?因为那似乎也不对。
【问题讨论】:
标签: c# json entity-framework asp.net-web-api json.net