C# api выдает ошибку «Типу ObjectContent`1 не удалось сериализовать тело ответа для типа контента application / xml; charset = utf-8 '». - PullRequest
0 голосов
/ 13 февраля 2020

Я точно следовал этому учебнику , но когда я запускаю свой код, я получаю это сообщение об ошибке.

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

}

Я также видел это решение , но это не работает для меня. Я все еще получаю сообщение об ошибке.

Любая помощь / советы приветствуются.

Заранее спасибо.

Ответы [ 2 ]

1 голос
/ 13 февраля 2020

Более ранние версии Entity Framework (т.е. до Core 2.1) использовали классы Proxy для моделей данных по умолчанию, когда он знает, что может лениво загружать данные. Например, если у вас был класс Parent с коллекцией класса Children, по умолчанию, когда вы загружаете объект Parent через что-то вроде этого

var parent = entities.Parents.FirstOrDefault(p=>p.Id==pid)

Тогда EF будет - по умолчанию - не загружать связанных потомков до тех пор, пока вы в первый раз не попытаетесь ссылаться на них

, например, только в том месте, где вы пишете

var child = parent.Children.Where(c=>c.SomeProperty==true)

, и будет отправлен запрос fre sh SQL для получения ребенок. Это возможно благодаря наличию (прозрачного для вас) прокси-класса, сгенерированного во время выполнения для объекта Parent, который обнаруживает, что вам нужен доступ к коллекции Children, и выдает SQL, выполняет сопоставление и т. Д. c .

К сожалению, эти прокси-классы плохо поддаются - если вообще - - сериализации по разным причинам. Отсюда и сообщение об ошибке, которое вы получаете. В EF Core 2.1 все изменилось, поэтому отложенная загрузка по умолчанию отключена, и вы должны включить ее. Но если вы используете любую более раннюю версию (включая неосновные EF), то она включена по умолчанию.

Это также объясняет, почему вы создаете новую базу данных без внешних ключей, потому что EF не сможет выводить отношения к дочерним объектам, поэтому он не будет создавать прокси, то есть класс, с которым вы имеете дело, теперь называется тем, что мы называем POCO (Plain Old CLR Object). Но вы лишаете себя (и EF) возможности иметь связанные объекты в реляционной базе данных, что, вероятно, не очень хорошо в долгосрочной перспективе:)

С точки зрения лучшего решения есть несколько вариантов Вы можете отключить создание прокси-сервера или получить весь объектный граф перед сериализацией:

var parent = entities.Parents.Include("Children").FirstOrDefault(p=>SomeCondition);

Это загрузит весь объект Parent и все его Children в одном go, и также избегайте проблемы; однако это не всегда идеально, потому что на самом деле вы не можете хотеть Children сущностей каждый раз.

Но еще лучше, не подвергайте ваши модели EF напрямую, а используйте отображение на DTO (Объект передачи данных)

Я рекомендую DTO; самое большое преимущество использования DTO состоит в том, что вам не нужно показывать свои EF-сущности внешнему миру, потому что, например, могут быть их части, не относящиеся к потребителю, или вы можете захотеть объединить данные для какого-либо ребенка сборы до возвращения, et c.

Здесь есть отличное руководство , в котором более подробно рассматриваются эти темы.

0 голосов
/ 13 февраля 2020

Видимо, это была проблема с моими внешними ключами в базе данных. Я создал новую базу данных с теми же данными, но без внешних ключей, и теперь мое приложение работает нормально.

Я надеюсь, что смогу помочь кому-то еще и с этим ответом.

...