【问题标题】:WebAPI OData Error The ObjectContent type failed to serialize the response body for content type 'application/json...'WebAPI OData 错误 ObjectContent 类型无法序列化内容类型“application/json ...”的响应正文
【发布时间】:2013-10-01 13:27:08
【问题描述】:

这个要杀了我。这里的文章和网络都没有帮助。

首先,我正在使用 .Net 4.5 开发 ASP.Net WebForms(不是 MVC)。我找到了一个great article,它可以帮助您将 OData 提要添加到您的 WebForms 站点。它像冠军一样工作。我能够创建一个 EMPTY Web 应用程序并让它工作。但是,我注意到它没有使用我通过this article 创建的最新(并且据说更容易)EntitySetController。两人分别工作。然后我按摩了原始文章,看看它是否可以处理EntitySetController,它可以。按照建议使用Fiddler 来测试OData 及其过滤。哦,快乐的一天。

我的下一步是将其添加到我现有的 ASP.Net 4.5 WebForms 应用程序中。让它有点工作。一切都编译好了,我可以调用locallhost:55777/kid,它按预期返回Products

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

然后我尝试GetGetEntityByKey 方法,它们运行并返回应有的内容。但是,我收到以下错误消息:

{
  "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()"
      }
    }
  }
}

控制器是:

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);
        }

    }
}

WebApiConfig 是:

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);
        }

    }
}

Global.asax.cs 文件的 Application_Start 仅包含以下内容:

WebApiConfig.Register(GlobalConfiguration.Configuration);

只是为了向您展示我在项目中有哪些包,这是我的Packages.config 文件。我知道Microsoft.AspNet.WebApi.* 项目是预发布的。我在当前的稳定版本中有它们,没有什么不同,所以我想我会尝试看看预发布是否能修复它。

<?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>

既然我可以让它独立工作,我认为有些东西会妨碍我。任何有用的帮助将不胜感激!蒂亚!

编辑 == 解决方案

感谢@RaghuRam,唯一需要更改的是 WebApiConfig 的 Register 方法。更新后的工作版本如下:

config.EnableQuerySupport();

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

IEdmModel model = modelBuilder.GetEdmModel();
config.Routes.MapODataRoute("ODataRoute", "kid", model);

太棒了!

【问题讨论】:

    标签: c# asp.net asp.net-web-api odata


    【解决方案1】:

    像这样使用 ODataConventionModelBuilder 而不是 ODataModelBuilder,

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

    ODataModelBuilder 是一个非常低级的类,用于显式配置整个模型时使用。您需要告诉它每个属性、每个导航属性,然后是自链接(id、编辑和读取)和导航链接。

    另一方面,ODataConventionModelBuilder 有一些约定可以自动推断这些事情。仅当您偏离约定时,您才需要使用 ODataConventionModelBuilder 显式配置某些内容。

    如果您仍然希望使用 ODataModelBuilder 类,您应该编写这样的代码,

    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();
    

    一旦有了导航属性和相关实体集等,事情就会变得更加复杂。

    【讨论】:

    • 请更新您的答案,您使用的是第一个示例中的旧答案
    猜你喜欢
    • 2017-07-17
    • 1970-01-01
    • 1970-01-01
    • 2017-12-13
    • 1970-01-01
    • 2012-10-07
    • 2015-06-27
    • 1970-01-01
    • 2012-12-07
    相关资源
    最近更新 更多