Introduction
One problem that I was facing yesterday while working on an ASP.NET MVC application was a JSON serialization issue. The problem was a circular reference caused by the DataContractJsonSerializer because of relations between the entity and other entities. In this post, I’ll show you how you can use a simple workaround in order to avoid the problem.
The JSON Serialization Error
Returning the output of the JSON method in an ASP.NET MVC controller with a JSON object graph based on an Entity Framework Code First object causes the following error – “A circular reference was detected while serializing an object of type ‘object name’”.
Here is an example of a method that might cause the problem:
public ActionResult Details(int id)
using (var context = new DbEntities())
{
var entity = context.Entities.
Include(e => e.OtherEntities).
FirstOrDefault(e => e.EntityId == id);
return Json(entity, JsonRequestBehavior.AllowGet);
}
}
Pay attention that this is a fake method and isn’t a real method.
The error I was getting didn’t show up on the server side (nothing crashed). I found the error by inspecting Fiddler since the application kept on working but the client side callback wasn’t. Here is an example of the calling client side function which is using jQuery getJSON
function:
function getDetails() {
$.getJSON('/ApplicationName/Details/' + Id, {}, function (data) {
fillDetails(data);
});
}
The circular reference is a known problem that my colleague Ido wrote about in Microsoft Connect.
So how to avoid it?
The Workaround
Use a data projection to project only the relevant data that you need and send this data to the client side. This workaround will minimize the object that you are sending and also play a role as a ViewModel
kind of object instead of an entity when it is available on the client side. Here is an example of using the workaround with the previous method:
public ActionResult Details(int id)
{
using (var context = new DbEntities())
{
var entity = context.Entities.
Include(g => g.OtherEntities).
Select(e => new {
e.Id,
e.Url,
e.Name,
e.OtherEntities
}).
FirstOrDefault(e => e.Id == id);
return Json(entity, JsonRequestBehavior.AllowGet);
}
}
Summary
The circular reference issue might happen also in WCF script services or in other places while serializing Entity Framework’s entities into JSON representation. The simple workaround is to create a projection of the data that you need and serialize it into JSON representation. One of the gains of this method is minimizing the response size from the server.