barteloma
barteloma

Reputation: 6875

Entity Framework relational result Web Api serialization error

I am using entity framwork in my Wep Api project. My model is realational and line this:

public class Blog
{
    public int Id { get; set; }
    public string Name { get; set; }

    public virtual ICollection<Article> Articles { get; set; }
}
public class Article
{
    public int Id { get; set; }
    public int BlogId { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }

    public virtual Blog Blog { get; set; }
}

context is like this:

public class BloggingContext: DbContext
{
    public DbSet<Blog> Blogs { get; set; }
    public DbSet<Article> Articles { get; set; }
}

And I am using this in my asp.net Web Api controller.

public class BlogController: ApiController{
      public IEnumerable<Blog> Get(){

           var context = new BloggingContext();

           return context.Blogs.ToList();
      }
}

My approach is to get data with Lazy Loading, and serialize to JSON data as Web Api response.

context.Blogs.ToList() returns the relational data (I see on breakpoint).

But Web Api result has error.

Exception Message:

The 'ObjectContent`1' type failed to serialize the response body for content type 'application/json; charset=utf-8

inner exception:

Error getting value from 'Blog' on 'System.Data.Entity.DynamicProxies.Article_D002A1ECE031410435306DCEF780AFF03EBB8BD36DA603662C993107FAEB1917 "ExceptionType": "Newtonsoft.Json.JsonSerializationException

I set my WebApiConfig.cs

 var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().First();
 jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
 jsonFormatter.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
 config.Formatters.Remove(config.Formatters.XmlFormatter);

Upvotes: 2

Views: 1983

Answers (3)

Heberda
Heberda

Reputation: 820

The old lazy loading questions! Such fun!

So firstly, when you breakpoint and evaluate an entity this by itself triggers lazy loading. Entity Framework is clever like that, but not helpful. When in fact, if you are not debugging, those same properties will be null.

You have 2 options here, 1. Eager Load or 2. As previously mentioned, use a transfer object. But why will they will.

  1. is obvious. by using context.Blogs.Include(x => x... etc) you are telling entity framework just to go ahead and load them because we will need it.

  2. Why does using a transfer object work? Well in order to transfer the data into the new object you must call the Get method on all properties within the old entity, thus triggering lazy loading. For this you can use 3rd party packages such as AutoMapper but they can cause overhead.

For an API I personally suggest Eager loading. The point of an API is that you as the develop design endpoints and you restrict what can and can't be used. If you want lazy loading then I suggest MVC is a better option.

Upvotes: 1

Aria
Aria

Reputation: 55

Try using data transfer objects in your controller.In my case this fixed the issue.BlogModel is the name of the new class that you have to add to use as DTO.It has the same properties as your entity class.

public IEnumerable<Blog> Get(){

       List<BlogModel> listofModels = new List<BlogModel>();
       foreach(var model in whateveristhenameofyourentity.Blogs)
              {
                     BlogModel blogModel = new BlogModel();
                     blogModel.name = model.name;
                     .
                     .
                     .
                     listofModels.Add(BlogModel);
              }
         IEnumerable<BlogModel> models = listofModels.AsIEnumerable();
         return models;
  }

Upvotes: 0

Grant H.
Grant H.

Reputation: 3717

You might try disabling proxy generation. At the minimum, that may give you a clearer exception if it doesn't fix the issue.

context.Configuration.ProxyCreationEnabled = false;

Upvotes: 2

Related Questions