c# - C# api 给出错误“'ObjectContent`1' 类型未能序列化内容类型 'application/xml; charset=utf-8' 的响应正文。”
问题描述
我完全按照本教程进行操作,但是当我运行我的代码时,我收到了这个错误消息。
<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.Player_B392F8ACFF7986B6E577FBE0EA4EC58EB44F1C4138CB96BE272A810004835B21' with data contract name 'Player_B392F8ACFF7986B6E577FBE0EA4EC58EB44F1C4138CB96BE272A810004835B21: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.SerializeWithXsiTypeAtTopLevel(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle originalDeclaredTypeHandle, Type graphType) 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.Web.Http.WebHost.HttpControllerHandler.<WriteBufferedResponseContentAsync>d__22.MoveNext()
</StackTrace>
</InnerException>
</Error>
我不明白我的代码在哪里失败,因为它与教程相同。
例如,控制器如下所示:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using UEFA_APIDataAcces;
namespace UEFA_API.Controllers
{
[RoutePrefix("api/Match")]
public class MatchController : ApiController
{
[Route("")]
public IEnumerable<Match> Get()
{
using(UEFAEntities entities = new UEFAEntities())
{
return entities.Match.ToList();
}
}
[Route("{id:int}")]
public Match Get(int id)
{
using (UEFAEntities entities = new UEFAEntities())
{
return entities.Match.FirstOrDefault(e => e.ID == id);
}
}
}
}
我也看到了这个解决方案,但这对我不起作用。我仍然收到错误消息。
欢迎任何帮助/提示。
先感谢您。
解决方案
较早的 Entity Framework 版本(即在 Core 2.1 之前)默认情况下使用代理类作为数据模型,因为它知道它可以延迟加载数据。例如,如果您有一个Parent
带有 class 集合的类Children
,默认情况下,当您Parent
通过类似这样的方式加载对象时
var parent = entities.Parents.FirstOrDefault(p=>p.Id==pid)
然后 EF 将 - 默认情况下 - 在您第一次尝试引用它们之前不会加载相关的孩子
例如只在你写的地方
var child = parent.Children.Where(c=>c.SomeProperty==true)
将发送一个新的 SQL 查询来获取孩子。这是通过在运行时为Parent
对象生成的(对您透明的)代理类来实现的,该代理类检测到您想要访问Children
集合并发出 SQL、进行映射等。
不幸的是,由于各种原因,这些 Proxy 类不适合序列化(如果有的话)。因此,您收到的错误消息。EF Core 2.1 改变了一些东西,默认情况下延迟加载是关闭的,你必须启用它。但是,如果您使用的是任何早期版本(包括非核心 EF),则默认情况下它处于打开状态。
这也可以解释为什么您在没有外键的情况下创建新数据库有效,因为 EF 将无法推断与子对象的关系,因此它不会创建代理,这意味着您正在处理的类现在是我们所说的POCO
(普通的旧 CLR 对象)。但是您正在剥夺自己(和 EF)在关系数据库中拥有相关对象的能力,从长远来看这可能不是一件好事:)
就更好的解决方案而言,有几个选项可以关闭代理创建,或者在序列化之前拉出整个对象图:
var parent = entities.Parents.Include("Children").FirstOrDefault(p=>SomeCondition);
这将一次性加载整个Parent
实体及其所有内容Children
,并避免该问题;但是,这并不总是理想的,因为您可能实际上并不每次都想要这些实体。Children
但更好的是,不要直接公开您的 EF 模型,而是使用映射到 DTO(数据传输对象)
我推荐 DTO;使用 DTO 的最大优点是您不需要将 EF 实体暴露给外界,因为例如它们中可能有部分与消费者无关,或者您可能想要对某个子对象进行聚合退货前的收集等
这里有一个很棒的指南,它更深入地讨论了这些主题。
推荐阅读
- json - 使用 play-json-extensions 反序列化 json 后添加其他字段
- javascript - 单击确认按钮后如何在相同的甜蜜框中显示文本?
- c# - 如何找到匹配所有字段的行
- java - 如何制作具有圆形排列组件的 GUI?
- react-native - FlatList 中的反应警告键
- android - iOS会破坏旋转视图吗?
- spring-boot - 防止 Spring 响应触发 EclipseLink 延迟加载
- javascript - Lottie Events 和 Lottie EventListeners 有什么区别以及如何使用?
- r - 根据 Col Y 中的条件从 Col X 中删除重复项
- curl - 如何检查网站是否使用 cookie 或不使用 Curl 命令?