JSON序列化. Net Web API)由于自引用循环而失败(这是一个常见的问题,原因:被请求的实体延迟加载子实体,并且每个子实体都有对父实体的反向引用)。
Work around I found, but not help me:
- 使用[JsonIgnore]来忽略导航属性:这个解决方案有效,但不适用于我的情况。例如:为了获得客户信息以及他的订单,我会快速将[JsonIgnore]添加到订单类中的客户属性,但是当我想获得订单信息以及客户详细信息时,因为在客户属性上有[JsonIgnore],所以它不会包括客户详细信息。
- 改变JSON。保留引用的Net序列化器设置:不能保存,因为我不需要循环引用数据。
- 在数据上下文中禁用代理创建并使用显式加载(这应该可以理想地解决问题):禁用代理创建停止延迟加载和返回数据没有错误,,但当我显式地包括子实体,我再次得到意外的自引用循环错误!错误位于父实体的反向引用级别。
有类似的经验/建议吗?
我尝试了所有建议的解决方案,但都不起作用。最后是重写JSON。. Net序列化器的DefaultContractResolver:
public class FilterContractResolver : DefaultContractResolver
{
Dictionary<Type, List<string>> _propertiesToIgnore;
public FilterContractResolver(Dictionary<Type, List<string>> propertiesToIgnore)
{
_propertiesToIgnore = propertiesToIgnore;
}
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
var property = base.CreateProperty(member, memberSerialization);
List<string> toIgnore;
property.Ignored |= ((_propertiesToIgnore.TryGetValue(member.DeclaringType, out toIgnore) || _propertiesToIgnore.TryGetValue(member.DeclaringType.BaseType, out toIgnore)) && toIgnore.Contains(property.PropertyName));
return property;
}
}
然后创建一个静态类,它返回一个基于控制器的要忽略的属性字典:
public static class CriteriaDefination
{
private static Dictionary<string, Dictionary<Type, List<string>>> ToIgnore = new Dictionary<string, Dictionary<Type, List<string>>>
{
{
"tblCustomer", new Dictionary<Type, List<string>>{
{
typeof(tblCustomer), new List<string>{
//include all
}
},
{
typeof(tblOrder), new List<string>{
"tblCustomer"//ignore back reference to tblCustomer
}
}
}
},
{
"tblOrder", new Dictionary<Type, List<string>>{
{
typeof(tblCustomer), new List<string>{
"tblOrders"//ignore back reference to tblOrders
}
},
{
typeof(tblOrder), new List<string>{
//include all
}
}
}
}
};
public static Dictionary<Type, List<string>> IgnoreList(string key)
{
return ToIgnore[key];
}
}
在每个控制器中修改JSON格式化器如下:
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new FilterContractResolver(CriteriaDefination.IgnoreList("tblCustomer"));
这就是我最终解决的问题,希望它能帮助到其他人。
假设EF类的结构是这样的:
public partial class MyEF
{
public virtual ICollection<MyOtherEF> MyOtherEFs {get; set;}
}
public partial class MyOtherEF
{
public virtual MyEF MyEF {get; set;}
}
保持序列化形式在JSON中发生。. NET中,你可以扩展这个类并添加一个名为"ShouldSerialize"+属性名的方法,如下所示:
public partial class MyEF
{
public bool ShouldSerializeMyOtherEFs() { return false; }
}
如果您想要更花哨一点,您可以在方法中添加逻辑,以便在某些情况下进行序列化。这允许您将序列化逻辑排除在EF Model First代码创建之外,只要该代码位于不同的物理代码文件中。
与其让实体框架生成模型,不如使用现有数据库的"代码优先"。现在你更能控制自己了。
查看Scott Guthrie的博客条目