Serializing Entity Framework objects to JSON in ASP.NET Web API

Β· 675 words Β· 4 minutes to read

Recently, I’ve been playing a lot with ASP.NET Web API, as it is really an exciting technology. It works exceptionally well with JSON.NET (Henrik Nielsen wrote a great post on how to return JSON from ASP.NET Web API using JSON.NET).

However, as it’s been the case in the past with i.e. WCF, I’ve run into a issue with serializing Entity Framework object to JSON when returning them from the ApiController. This is not, by any means, an issue in ASP.NET Web API, as the problem in this case lies in the EF lazy loading, which causes circular reference between the objects. This then throws a corresponding error - “A circular reference was detected while serializing an object of type (…)” if you are using JavaScriptSerializer, “Self referencing loop detected for type (…)” if you are using JSON.NET and so on.

I thought it might be useful to remind about possible solutions to this. There is an easy workaround.

More after the jump.

Our models & errors πŸ”—

For starters let’s take a look at our two simple models.

public class Url  
{  
public int UrlId { get; set; }  
public string Address { get; set; }  
public string Description { get; set; }  
public string Uid { get; set; }  
public virtual List<Tag> Tags { get; set; }  
}  
public class Tag  
{  
public int TagId { get; set; }  
public string Name { get; set; }  
}  

And the DbContext.

public class UrlzipContext : DbContext  
{  
public DbSet<Url> Urls { get; set; }  
public DbSet<Tag> Tags { get; set; }  
}  

Finally, here is our ApiController.

public class ValuesController : ApiController  
{  
DbContext db = new DbContext();  
// GET /api/values  
public List<Url> Get()  
{  
var urls = db.Urls.Include("Tags").ToList();  
return urls;  
}  
}  

If we try to return a simple Url from the ApiController, using the example above, we’d get the following error (note, the error comes from JSON.NET, but any other serializer would throw similar.

Solution - data projection πŸ”—

Data projection - in other words, passing to serializer only a selected set of values, in a form of an object different from Domain Model Object. DTO is a massive topic on its own, so I will not discuss it here. In case you are interested, there is a great article on that here. In short, let’s just say that many people consider using DTO these days a very poor approach, while others firmly believe that it is abolutely necessary to use DTO instead of trying to serialize your Domain Model Objects. Personally, I am a data projection advocate as to me it only makes sense to NOT expose domain models to the View.

Anyway, moving aside from the discussion, we could use data projection to an anonymous type in the LINQ query and serialize that. In other words, that would act kind of like a ViewModel.

var urls = db.Urls.Include("Tags").Select(i =>  
new { i.Uid, i.UrlId, i.Address, i.Description, i.Tags});  

This still wouldn’t compile as our old Get() method was returning a List, whereas in here we are dealing with IQueryable of Anonymous Type. Unfortunately there is no simple way to return IQueryable of Anonymous Type or IEnumerable of Anonymous Type from an ApiController method. So we’ll use a bit of hack and change the method signature to:

public dynamic Get()  

This is C# 4.0+ only, but we are talking ASP.NET Web API here, aren’t we? So the whole thing now looks like this:

public dynamic Get()  
{  
var urls = db.Urls.Include("Tags").Select(i =>  
new { i.Uid, i.UrlId, i.Address, i.Description, i.Tags});  
return urls;  
}  

Of course in this case we lose the type safety, but again, it produces the expected result.

Summary πŸ”—

If you run into problems with your EF objects, do not worry, there are ways to work around them. I’ve found this solution useful when experimenting with ASP.NET Web API, especially with much more complex entities that the ones used here as an example. If you don’t entirely agree, instead of returning anonymous object, you can also return a custom type, and effectively have a ViewModel.

About


Hi! I'm Filip W., a cloud architect from ZΓΌrich πŸ‡¨πŸ‡­. I like Toronto Maple Leafs πŸ‡¨πŸ‡¦, Rancid and quantum computing. Oh, and I love the Lowlands 🏴󠁧󠁒󠁳󠁣󠁴󠁿.

You can find me on Github and on Mastodon.

My Introduction to Quantum Computing with Q# and QDK book
Microsoft MVP