ASP.NET Web API序列化JSON错误:“自我引用循环”

时间:2014-05-30 22:44:54

标签: c# asp.net json asp.net-web-api

与这一次长期斗争。我正在使用ASP.NET Web API为数据库提供干净,轻松的HTTP / JSON交互。我有一个实体名称Reservation with,如下所示:

    // Reservation
public class Reservation
{
    public int ID { get; set; } // ID (Primary key)
    public int EquipmentID { get; set; } // EquipmentID
    public string Username { get; set; } // Username
    public DateTime BeginDateTime { get; set; } // BeginDateTime
    public int? Duration { get; set; } // Duration
    public int? ReservationStateID { get; set; } // ReservationStateID
    public DateTime? CheckInDateTime { get; set; } // CheckInDateTime
    public string Note { get; set; } // Note

    // Foreign keys
    public virtual Equipment Equipment { get; set; } // FK_Reservation_EquipmentID
    public virtual ReservationState ReservationState { get; set; } //FK_Reservation_ReservationState
}

到目前为止一切顺利。我正在运行一个简单的python脚本来创建一个新的预留,与http请求一起传递一个Reservation JSON对象。在以前的生活中,我运行预订添加代码而不进行数据验证,并在HttpActionResult中返回Reservation对象。我所看到的是一个很好的json对象:

  

{u'用户名':你'姓名',你' ReservationStateID':1,你'设备':无,你' EquipmentID&# 39;:2,你' BeginDateTime&#39 ;: u' 2014-05-31T14:00:00Z',你'注意':你'',你& #39; CheckInDateTime':无,你'持续时间':10800,你' ReservationState':无,你' ID':51}

我有点担心返回的对象中包含的外键设备和ReservationState,这可能会导致更大的问题,但是在适当的时候。 现在我尝试通过收集预订引用的设备项来运行数据验证

Equipment equipmentItem = await db.Equipment.FindAsync(newRes.EquipmentID);

现在,当我尝试执行相同的操作时,在同一个python脚本上使用相同的数据,收到的结果是一个很大的可怕错误:

  

"' ObjectContent`1'类型无法序列化内容类型的响应主体' application / json; charset = utf-8'。",你' StackTrace':没有,你'消息':你'发生错误。',你&# 39; InnerException':{u' ExceptionMessage':u"检测到属性的自我参考循环'设备'类型......

我99%肯定我的数据库中的外键不会创建循环引用,但我在这里唉。 我想再次指出将外键包含在"成功"杰森的结果。如果我可以摆脱那些我可以摆脱自我引用问题的赌注,我打赌。谢谢你的帮助!

2 个答案:

答案 0 :(得分:6)

错误是由EF为外键对象创建代理引起的,当使用代理序列化时,默认序列化程序(DataContractSerializer)错误。解决方案是将以下行添加到Global.asax.cs文件中:

GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore; 

虽然@ SKall的答案确实解决了问题,但它并没有在整个项目中解决它,只是对我给出了IgnoreDataMember属性的属性。

答案 1 :(得分:4)

使用IgnoreDataMember属性标记引用,如果有帮助,请告诉我们。

[IgnoreDataMember]
public virtual Equipment Equipment { get; set; }

[IgnoreDataMember]
public virtual ReservationState ReservationState { get; set; }