从 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>
问题是它也在尝试序列化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。