簡體   English   中英

WebAPI OData錯誤ObjectContent類型無法序列化內容類型'application / json ...'的響應正文

[英]WebAPI OData Error The ObjectContent type failed to serialize the response body for content type 'application/json…'

這個是殺了我。 這里的文章和網絡都沒有幫助。

首先,我正在使用.Net 4.5開發ASP.Net WebForms(非MVC)。 我發現了一篇很棒的文章 ,可以幫助您向WebForms站點添加OData源。 它像一個冠軍一樣工作。 我能夠創建一個EMPTY Web應用程序並使其工作。 但是,我注意到它沒有使用我通過本文創建的最新(並且應該更容易)的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>

由於我可以獨立工作,我覺得有些事情正在阻礙。 任何有用的幫助將不勝感激! TIA!

編輯==解決方案

感謝@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);

真棒!

而不是ODataModelBuilder,像這樣使用ODataConventionModelBuilder,

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

一旦有了導航屬性和相關的實體集等,事情會變得更加復雜。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM