首页 > 解决方案 > 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);
            }
        }
    }

}

我也看到了这个解决方案,但这对我不起作用。我仍然收到错误消息。

欢迎任何帮助/提示。

先感谢您。

标签: c#.netentity-frameworkapiasp.net-web-api

解决方案


较早的 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 实体暴露给外界,因为例如它们中可能有部分与消费者无关,或者您可能想要对某个子对象进行聚合退货前的收集等

这里有一个很棒的指南,它更深入地讨论了这些主题。


推荐阅读