【问题标题】:Returning Entity Framework class from Web API throws "failed to serialize the response body for content type" exception从 Web API 返回实体框架类会引发“无法序列化内容类型的响应主体”异常
【发布时间】:2016-07-07 23:15:44
【问题描述】:

我面临以下问题,我有一个对象模型 BlogEntry:

public class BlogEntry
    {
        public int Id { get; set; }
        [Required]
        public DateTime BlogEntryDate { get; set; }
        [Required]
        public string BlogEntryTitle { get; set; }
        [Required]
        public string BlogEntrySummary { get; set; }
        [Required]
        public string BlogEntryContent { get; set; }
        [Required]
        public string BlogEntryPublishedBy { get; set; }
        [Required]
        public bool BlogEntryPublished { get; set; }
        public int BlogCategoryId { get; set; }
        public virtual BlogCategory BlogCategory { get; set; }
    }

我用模型生成了控制器,我有方法:

 // GET: api/BlogEntries
        [AllowAnonymous]
        public IQueryable<BlogEntry> GetBlogEntries()
        {
            return db.BlogEntries;
        }

问题是当我测试方法时序列化出错:

“ObjectContent`1”类型未能序列化响应正文 内容类型'应用程序/xml;字符集=utf-8'

我尝试在 WebAPIConfig.cs 中使用以下代码进行修复:

 config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));
            config.Formatters.JsonFormatter
                        .SerializerSettings
                        .ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;

实际上这在本地解决了问题,但是当我将应用程序发布到 Azure 时,一直给我错误代码 500。 注:我调试了方法,代码没有问题,其实很简单。

有什么建议

浏览器异常

<Error>
<Message>An error has occurred.</Message>
<ExceptionMessage>
The 'ObjectContent`1' type failed to serialize the response body for content type 'application/xml; charset=utf-8'.
</ExceptionMessage>
<ExceptionType>System.InvalidOperationException</ExceptionType>
<StackTrace/>
<InnerException>
<Message>An error has occurred.</Message>
<ExceptionMessage>
Type 'System.Data.Entity.DynamicProxies.BlogEntry_2BC5105C1EBC22432CBA0E820087939FDB4E152CC4026BA3BC6DDDD9C1156A4D' with data contract name 'BlogEntry_2BC5105C1EBC22432CBA0E820087939FDB4E152CC4026BA3BC6DDDD9C1156A4D:http://schemas.datacontract.org/2004/07/System.Data.Entity.DynamicProxies' is not expected. Consider using a DataContractResolver if you are using DataContractSerializer or add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to the serializer.
</ExceptionMessage>
<ExceptionType>
System.Runtime.Serialization.SerializationException
</ExceptionType>
<StackTrace>
at System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeAndVerifyType(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, Boolean verifyKnownType, RuntimeTypeHandle declaredTypeHandle, Type declaredType) at System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeWithXsiType(XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle objectTypeHandle, Type objectType, Int32 declaredTypeID, RuntimeTypeHandle declaredTypeHandle, Type declaredType) at System.Runtime.Serialization.XmlObjectSerializerWriteContext.InternalSerialize(XmlWriterDelegator xmlWriter, Object obj, Boolean isDeclaredType, Boolean writeXsiType, Int32 declaredTypeID, RuntimeTypeHandle declaredTypeHandle) at WriteArrayOfBlogEntryToXml(XmlWriterDelegator , Object , XmlObjectSerializerWriteContext , CollectionDataContract ) at System.Runtime.Serialization.CollectionDataContract.WriteXmlValue(XmlWriterDelegator xmlWriter, Object obj, XmlObjectSerializerWriteContext context) at System.Runtime.Serialization.XmlObjectSerializerWriteContext.WriteDataContractValue(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle declaredTypeHandle) at System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeWithoutXsiType(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle declaredTypeHandle) at System.Runtime.Serialization.DataContractSerializer.InternalWriteObjectContent(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver) at System.Runtime.Serialization.DataContractSerializer.InternalWriteObject(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver) at System.Runtime.Serialization.XmlObjectSerializer.WriteObjectHandleExceptions(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver) at System.Runtime.Serialization.DataContractSerializer.WriteObject(XmlWriter writer, Object graph) at System.Net.Http.Formatting.XmlMediaTypeFormatter.WriteToStream(Type type, Object value, Stream writeStream, HttpContent content) at System.Net.Http.Formatting.XmlMediaTypeFormatter.WriteToStreamAsync(Type type, Object value, Stream writeStream, HttpContent content, TransportContext transportContext, CancellationToken cancellationToken) --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter.GetResult() at System.Web.Http.WebHost.HttpControllerHandler.<WriteBufferedResponseContentAsync>d__1b.MoveNext()
</StackTrace>
</InnerException>
</Error>

【问题讨论】:

  • 能否上传您在 Azure 中收到的异常消息?
  • 我不确切知道如何获取异常,但我正在使用 javascript 调用该方法,并且收到错误代码 500,当我执行 url 时,我得到了 {"Message":"An error has occurred."}
  • @Win 我用收到的回复更新了问题。

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


【解决方案1】:

问题是它也在尝试序列化 BlogCategory。

public virtual BlogCategory BlogCategory { get; set; }

首先,从 Web API(或任何 API)返回 Entity 类并不是一个好习惯。通常,我们将 Entity 映射到 DTO(数据传输对象)。

最简单的测试方法是创建一个 DTO 类 -

public class BlogEntryModel
{
    public int Id { get; set; }
    public DateTime BlogEntryDate { get; set; }
    public string BlogEntryTitle { get; set; }
    public string BlogEntrySummary { get; set; }
    public string BlogEntryContent { get; set; }
    public string BlogEntryPublishedBy { get; set; }
    public bool BlogEntryPublished { get; set; }
    public int BlogCategoryId { get; set; }
}

然后返回它而不是 BlogEntry。

return db.BlogEntries
    .Select(x => new BlogEntryModel
    {
        Id = x.Id,
        ...
    })
    .ToList();

正确的方法是使用AutoMapper 和存储库模式,但它超出了原始问题的范围,我不想偏离 OP。

【讨论】:

  • 谢谢@Win,但是如果我去掉public virtual BlogCategory BlogCategory { get; set; }当我生成数据库时Entity框架会明白那些表是相关的吗?
  • 您不想删除它;它会破坏表之间的关系。
  • 抱歉,解决办法是什么?
  • 好吧,至少你可以测试上面的代码,以确保它解决了主要问题。之后,您可以决定如何改进代码。 仅供参考:返回实体类绝对不是任何 API 开发的好习惯。
猜你喜欢
  • 2016-02-07
  • 1970-01-01
  • 2012-10-07
  • 1970-01-01
  • 1970-01-01
  • 2016-10-10
  • 2018-01-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多