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

Strath

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

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.

And the DbContext.

Finally, here is our ApiController.

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.

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:

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:

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.

Be Sociable, Share!

  • Pingback: Dew Drop – March 22, 2012 (#1,292) | Alvin Ashcraft's Morning Dew

  • Pingback: Interesting .NET Links - March 22 , 2012 | Tech Blog

  • http://freshbrewedcode.com/jonathancreamer Jonathan Creamer

    FYI, you can also disable Lazy Loading in the constructor of the dbContext… I.E.
    public DbContext(){
    Configuration.LazyLoadingEnabled = false;
    }
    Then you won’t have to do it every time you need to use your DbContext.

  • mycall

    It should be noted that the use of dynamic might not work in medium trust mode.

  • http://aquabirdconsulting.com Khalid Abuhakmeh

    Projection makes the most sense to me, since there might be sensitive / internal data on your models that doesn’t make sense to expose in an API.

    Seems like a better rule of thumb, considering your application could change over time while people could be dependent on or API staying the same.

  • http://www.dotnettechy.com Dotnet techy

    Great article

    We can also submit our .net related article links on http://www.dotnettechy.com to improve traffic.

    This website also have directory submission for .net related website / blog only

  • Nadav

    Great Article! Simple and very useful. I’ve been looking for this for hours.

  • Shamim

    Thanks a lot for this solution. It saved lots of hours

  • Mark

    Hi – this looks like it’s describing a problem I posted on SO: http://stackoverflow.com/questions/10897523/asp-net-web-api-showing-correctly-in-vs-but-giving-http500

    However, I can’t get VS to compile, because of the type safety issue. Do you have any pointers on how to get around that please?

    thanks for your help,

    Mark

  • Mike

    Great article. If you wanted you could also use a viewmodel approach. While you are returning a view per se, you return a model designed around what you want exposed in the API.

    public list Get()
    {
    var urls = db.Urls.Include(“Tags”).Select(i =>
    new ViewModels.Url { i.Uid, i.UrlId, i.Address, i.Description, i.Tags});
    return urls;
    }

    That’s how i usually get around issues with dynamic and type safety.

    • Filip W

      Very good point!

  • tcrao

    entities.ContextOptions.LazyLoadingEnabled = false;
    this is worked

    your suggestions are not working for me