2

Been a long struggle with this one. I'm working with an ASP.NET web API to provide clean and easy HTTP/JSON interaction with a database. I have an entity name Reservation with that looks as following:

    // 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
}

So far so good. I am running a simple python script to create a new reservation, passing along with the http request a Reservation JSON object. In a previous life I ran the reservation adding code without data validation and returned the Reservation object in the HttpActionResult. What I saw in return was a nice json object:

{u'Username': u'name', u'ReservationStateID': 1, u'Equipment': None, u'EquipmentID': 2, u'BeginDateTime': u'2014-05-31T14:00:00Z', u'Note': u'', u'CheckInDateTime': None, u'Duration': 10800, u'ReservationState': None, u'ID': 51}

I am a little concerned with the foreign keys Equipment and ReservationState being included in the returned object, which may lend to the larger problem, but that in due time. Now I try to run data validation by gathering the Equipment item referenced by my Reservation.

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

Now when I try to perform the same action, using the same data on the same python script the result received is a big scary error:

"The 'ObjectContent`1' type failed to serialize the response body for content type 'application/json; charset=utf-8'.", u'StackTrace': None, u'Message': u'An error has occurred.', u'InnerException': {u'ExceptionMessage': u"Self referencing loop detected for property 'Equipment' with type...

I am 99% positive that the foreign keys in place in my database do not create circular references, but alas here I am. Again I want to point out the inclusion of the foreign keys in the "successful" json results. I'm betting if I can be rid of those I can be rid of the self referencing issue. Thanks for the help!

Freestyle076
  • 1,548
  • 19
  • 36
  • Possible duplicate of [JSON.NET Error Self referencing loop detected for type](https://stackoverflow.com/questions/7397207/json-net-error-self-referencing-loop-detected-for-type) – NH. Oct 31 '17 at 20:37

2 Answers2

6

The error was caused by the EF creating proxies for the foreign key objects, the default serializer (DataContractSerializer) errors when serializing with proxies. The solution is to add the following line to the Global.asax.cs file:

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

While @SKall's answer did solve the problem, it didn't solve it throughout the project, just to properties that I gave the IgnoreDataMember attribute.

Freestyle076
  • 1,548
  • 19
  • 36
  • Does that solution solve the problem with other serializers as well, or just Json.NET? – SKall Jun 08 '14 at 14:14
  • I'm not quite sure. I'm not using any other serializers, but I imagine that sense I'm editing the configurations for the JsonFormatter that only Json.NET is affected. Has anyone tried this on say an XML serializer? – Freestyle076 Jun 09 '14 at 15:21
  • I guess by default on ASP.NET pages the formatter is the one from NewtonSoft so the dependency to Json.NET is hard coded in. I don't think that setting has any effect on other JSON serializers. Just FYI in case you at some point have the need for faster serializers. – SKall Jun 09 '14 at 16:13
4

Mark the references with IgnoreDataMember attribute and let us know if that helped.

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

[IgnoreDataMember]
public virtual ReservationState ReservationState { get; set; }
SKall
  • 5,234
  • 1
  • 16
  • 25