воскресенье, 16 сентября 2012 г.

Serializing Entity Framework Objects into JSON Using ASP.Net MVC


I’ve been working with the Entity Framework 4 on a new MVC2 application recently and one apparently simple task had been doing my head in for a full day. The problem was when I tried to serialize a list entity object using the Json method in a JsonResult action. Every time I tried, no matter how I approached the task of retrieving the records, I’d always see the following exception in my Json response:
A circular reference was detected while serializing an object of type ‘System.Data.Metadata.Edm.AssociationType’.
The really frustrating part was that when I was debugging my application in Visual Studio, everything appeared to be working just fine. Connections were established, records were returned and could be passed into my List object.
As it turns out, the problem appears to be a native issue with the DataContractJsonSerializer support for Entity types.  In short, Entities that have relationships (i.e. two-way) with other Entity types cannot be serialised through Json.  For example, a Customer table connected to an Orders table will not translate well into Json serializing because a Customer may have many orders and an Order is associated with a Customer.
Eugene Osovetsky, Program Manager (Connected Framework Client) at Microsoft has the following to say about the issue:
The lack of DataContractJsonSerializer support for Entity types is certainly an important feature hole, and we will certainly be investigating possible solutions in future versions. Unfortunately, the current serialization model only allows one projection per type, EDM type generation only allows generating IsReference=true types, and there is no standard way of encoding references in JSON. Clearly one of these 3 constraints has to give for this to be solved, but all have problems. Multiple projections would be great, but may be complex to understand/use and would be a major new feature (it is on our radar for the future).
One approach to solving this problem has been:
…to make the serializer ignore the properties of type EntityReference, using an empty implementation of a class deriving from JavaScriptConverter and registering it using the RegisterConverters method of the JavaScriptSerializer object.
However, I feel that for most cases, this is overly complex and requires more thought than most situations would likely demand.  A better approach IMHO would be to take a collection of results and extract your required properties into a new anonymous type.  The thinking here is that if you’re returning Json objects through Ajax calls, you’re probably only interested in values rather than the full behaviours of a given object.  Therefore, the following code sorted my problem out adequately:
public JsonResult Orders()
    var results = from Ord in databaseContext.Orders
              select new
              {
                  OrderID = Ord.ID,
                  OrderTitle = Ord.Name,
                  OrderDate = Ord.OrderDate
              }

    return Json(results);
}
This is an easier approach because I gain control and flexibility in exactly what values are returned in my Json response, I can ignore completely the buggy nature of the DataContractJsonSerializer and I’m serializing only the object parts I’m concerned with.

Комментариев нет: