WebAPI OData Error The ObjectContent type failed to serialize the response body for content type 'application/json...'

10,989

Instead of the ODataModelBuilder, use ODataConventionModelBuilder like this,

var modelBuilder = new ODataConventionModelBuilder ();
var products = modelBuilder.EntitySet<Product>("Products");

IEdmModel model = modelBuilder.GetEdmModel();

ODataModelBuilder is a very low level class intended to be used when you want to configure the whole model explicitly. You need to tell it each and every property, each and every navigation property and then the self-links (id, edit and read) and the navigation links.

ODataConventionModelBuilder on the other hand, has some conventions to infer these things automatically. You need to configure something explicitly with the ODataConventionModelBuilder only if you deviate from the conventions.

If you still wish to use the ODataModelBuilder class, you should write code like this,

ODataModelBuilder modelBuilder = new ODataModelBuilder();
var products = modelBuilder.EntitySet<Product>("Products");
var product = products.EntityType;

product.HasKey(p => p.ID);
product.Property(p => p.Name);
product.Property(p => p.Price);
product.Property(p => p.Category);

products.HasIdLink((ctxt) => ctxt.Url.ODataLink(new EntitySetPathSegment("Products"), new KeyValuePathSegment(ctxt.EntityInstance.ID)));

IEdmModel model = modelBuilder.GetEdmModel();

Things get more complicated once you have navigation properties and related entitysets etc.

Share:
10,989

Related videos on Youtube

Grandizer
Author by

Grandizer

I am a .Net programmer by day and a beer enthusiast by night. I am also a bicyclist and do a great American Cancer Society charity bike ride called the Pan Ohio Hope Ride. If you want to join my team, volunteer or donate, please click here.

Updated on September 15, 2022

Comments

  • Grandizer
    Grandizer almost 2 years

    This one is killing me. None of the articles here nor the web have helped.

    To start with, I am working on an ASP.Net WebForms (Not MVC) using .Net 4.5. I found a great article that helps you add an OData feed to your WebForms site. It worked like a champ. I was able to create an EMPTY Web Application and get it to work. However, I noticed that it was not using the latest (and supposedly easier) EntitySetController which I had created via this article. Both worked separately. I then massaged the original article to see if it could handle the EntitySetController and it could. Used Fiddler as suggested to test the OData and its filtering. Oh happy day.

    My next step was to add that to my existing ASP.Net 4.5 WebForms application. Got it working somewhat. Everything compiles and I can make a call to locallhost:55777/kid and it returns Products as expected:

    <workspace>
      <atom:title type="text">Default</atom:title>
      <collection href="Products">
        <atom:title type="text">Products</atom:title>
      </collection>
    </workspace>
    

    I then try the Get or GetEntityByKey methods and they run and give back what they should. However, I get the following error message:

    {
      "odata.error":{
        "code":"","message":{
          "lang":"en-US","value":"An error has occurred."
        },
        "innererror":{
          "message":"The 'ObjectContent`1' type failed to serialize the response body for content type 'application/json; odata=minimalmetadata; streaming=true; charset=utf-8'.",
          "type":"System.InvalidOperationException",
          "stacktrace":"",
          "internalexception":{
            "message":"No IdLink factory was found. Try calling HasIdLink on the EntitySetConfiguration for 'Products'.",
            "type":"System.InvalidOperationException",
            "stacktrace":"   at System.Web.Http.OData.Builder.EntitySetLinkBuilderAnnotation.BuildIdLink(EntityInstanceContext instanceContext, ODataMetadataLevel metadataLevel)\r\n
                             at System.Web.Http.OData.Builder.EntitySetLinkBuilderAnnotation.BuildEntitySelfLinks(EntityInstanceContext instanceContext, ODataMetadataLevel metadataLevel)\r\n   
                             at System.Web.Http.OData.Formatter.Serialization.ODataEntityTypeSerializer.CreateEntry(SelectExpandNode selectExpandNode, EntityInstanceContext entityInstanceContext)\r\n   
                             at System.Web.Http.OData.Formatter.Serialization.ODataEntityTypeSerializer.WriteEntry(Object graph, ODataWriter writer, ODataSerializerContext writeContext)\r\n   
                             at System.Web.Http.OData.Formatter.Serialization.ODataEntityTypeSerializer.WriteObjectInline(Object graph, IEdmTypeReference expectedType, ODataWriter writer, ODataSerializerContext writeContext)\r\n
                             at System.Web.Http.OData.Formatter.Serialization.ODataEntityTypeSerializer.WriteObject(Object graph, Type type, ODataMessageWriter messageWriter, ODataSerializerContext writeContext)\r\n   
                             at System.Web.Http.OData.Formatter.ODataMediaTypeFormatter.WriteToStream(Type type, Object value, Stream writeStream, HttpContent content, HttpContentHeaders contentHeaders)\r\n   
                             at System.Web.Http.OData.Formatter.ODataMediaTypeFormatter.WriteToStreamAsync(Type type, Object value, Stream writeStream, HttpContent content, TransportContext transportContext)\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   
                             at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n
                             at System.Runtime.CompilerServices.TaskAwaiter.GetResult()\r\n   
                             at System.Web.Http.WebHost.HttpControllerHandler.<WriteBufferedResponseContentAsync>d__10.MoveNext()"
          }
        }
      }
    }
    

    The Controller is:

    using System.Collections.Generic;
    using System.Linq;
    using System.Web.Http.OData;
    
    namespace BOR.InternalWebsite.Controllers {
    
        public class ProductsController : EntitySetController<Product, int> {
    
            static List<Product> products = new List<Product>() {
                new Product() { ID = 1, Name = "Hat", Price = 15, Category = "Apparel" },
                new Product() { ID = 2, Name = "Socks", Price = 5, Category = "Apparel" },
                new Product() { ID = 3, Name = "Scarf", Price = 12, Category = "Apparel" },
                new Product() { ID = 4, Name = "Yo-yo", Price = 4.95M, Category = "Toys" },
                new Product() { ID = 5, Name = "Puzzle", Price = 8, Category = "Toys" },
            };
    
            public override IQueryable<Product> Get() {
                return products.AsQueryable();
            }
    
            protected override Product GetEntityByKey(int key) {
                return products.FirstOrDefault(p => p.ID == key);
            }
    
        }
    }
    

    The WebApiConfig is:

    using Microsoft.Data.Edm;
    using System.Web.Http;
    using System.Web.Http.OData.Builder;
    
    namespace BOR.InternalWebsite {
    
        public static class WebApiConfig {
    
            public static void Register(HttpConfiguration config) {
                config.EnableQuerySupport();
    
                ODataModelBuilder modelBuilder = new ODataModelBuilder();
                var products = modelBuilder.EntitySet<Product>("Products");
    
                IEdmModel model = modelBuilder.GetEdmModel();
                config.Routes.MapODataRoute("ODataRoute", "kid", model);
            }
    
        }
    }
    

    The Global.asax.cs file's Application_Start has nothing but the following:

    WebApiConfig.Register(GlobalConfiguration.Configuration);
    

    Just to show you what packages I have in the project, here is my Packages.config file. I do know that the Microsoft.AspNet.WebApi.* items are pre-release. I had them in the current stable release and nothing was different so I thought I would try to see if the pre-release would fix it.

    <?xml version="1.0" encoding="utf-8"?>
    <packages>
        <package id="DynamicDataTemplatesCS" version="1.0.1" targetFramework="net45" />
        <package id="elmah" version="1.2.2" targetFramework="net45" />
        <package id="elmah.corelibrary" version="1.2.2" targetFramework="net45" />
        <package id="EntityFramework" version="5.0.0" targetFramework="net45" />
        <package id="jQuery" version="2.0.3" targetFramework="net45" />
        <package id="jquery.mobile" version="1.3.2" targetFramework="net45" />
        <package id="jQuery.UI.Combined" version="1.10.3" targetFramework="net45" />
        <package id="knockoutjs" version="2.3.0" targetFramework="net45" />
        <package id="Microsoft.AspNet.WebApi" version="5.0.0-rc1" targetFramework="net45" />
        <package id="Microsoft.AspNet.WebApi.Client" version="5.0.0-rc1" targetFramework="net45" />
        <package id="Microsoft.AspNet.WebApi.Core" version="5.0.0-rc1" targetFramework="net45" />
        <package id="Microsoft.AspNet.WebApi.OData" version="5.0.0-rc1" targetFramework="net45" />
        <package id="Microsoft.AspNet.WebApi.WebHost" version="5.0.0-rc1" targetFramework="net45" />
        <package id="Microsoft.Bcl" version="1.1.3" targetFramework="net45" />
        <package id="Microsoft.Bcl.Build" version="1.0.10" targetFramework="net45" />
        <package id="Microsoft.Data.Edm" version="5.6.0" targetFramework="net45" />
        <package id="Microsoft.Data.OData" version="5.6.0" targetFramework="net45" />
        <package id="Microsoft.Net.Http" version="2.2.15" targetFramework="net45" />
        <package id="Newtonsoft.Json" version="5.0.6" targetFramework="net45" />
        <package id="System.Spatial" version="5.6.0" targetFramework="net45" />
        <package id="Twitter.Bootstrap" version="3.0.0" targetFramework="net45" />
    </packages>
    

    Since I can get this to work stand-alone, I figure something is getting in the way. Any useful help would be greatly appreciated! TIA!

    EDIT == SOLUTION

    Thanks to @RaghuRam the only thing that needed changing was the WebApiConfig's Register method. The updated and thus working version is as follows:

    config.EnableQuerySupport();
    
    ODataConventionModelBuilder modelBuilder = new ODataConventionModelBuilder();
    var products = modelBuilder.EntitySet<Product>("Products");
    
    IEdmModel model = modelBuilder.GetEdmModel();
    config.Routes.MapODataRoute("ODataRoute", "kid", model);
    

    Awesome!

  • Leandro Bardelli
    Leandro Bardelli almost 10 years
    please update your answer, you are using the old one in the first example