从 Web API 返回实体框架类会引发“无法序列化内容类型的响应正文”异常

本文关键字:序列化 类型 异常 正文 响应 实体 返回 API Web 框架 | 更新日期: 2023-09-27 17:55:43

我面临以下问题,我有一个对象模型博客条目:

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

问题是当我测试该方法时,序列化中出现错误:

"

对象内容"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>

从 Web API 返回实体框架类会引发“无法序列化内容类型的响应正文”异常

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

public virtual BlogCategory BlogCategory { get; set; }

首先,从 Web API(或任何与此相关的 API)返回实体类不是一个好的做法。通常,我们将实体映射到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。