Falha ao serializar a resposta na API da Web


86

Eu estava trabalhando na API da web ASP.NET MVC, estou tendo este erro:

O tipo 'ObjectContent`1' falhou ao serializar o corpo da resposta para o tipo de conteúdo 'application / xml; charset = utf-8 '.

Meu controlador é:

public Employee GetEmployees()
{
    Employee employees = db.Employees.First();
    return employees;
}

por que estou recebendo este erro?


6
A exceção que você está vendo é uma exceção geral, que pode ser causada por uma série de fatores. Verifique a InnerExceptionpropriedade da exceção de serialização para descobrir o que exatamente causou a falha da serialização.
Nome de exibição

Você pode compartilhar o código para o seu tipo de funcionário? Pode ser porque o tipo Employee não é serializável ...
Maggie Ying

Também dê uma olhada neste stackoverflow.com/questions/8173524/…
sttaq

Respostas:


121

Para mim, esse era um problema de referência circular.

A resposta aceita não funcionou para mim porque ela apenas altera o comportamento do formatador JSON, mas eu estava recebendo XML quando chamei o serviço do navegador.

Para corrigir isso, desliguei o XML e forcei apenas o retorno de JSON.

No arquivo Global.asax, coloque as seguintes linhas na parte superior do seu método Application_Start:

GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
GlobalConfiguration.Configuration.Formatters.Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter);

Agora, apenas resultados JSON serão retornados. Se precisar de resultados XML, você precisará encontrar uma solução diferente.


funcionou para mim. mas o problema é que estou usando o POSTMAN. é uma extensão do Chrome. quando eu posto dados com o POSTMAN, ele funciona bem. mas quando eu uso o restsharp, ele me dá esse erro. de qualquer forma, sua solução corrigiu meu problema
ArgeKumandan

Essa resposta não fornece uma solução para usar xml, e foi isso que ele pediu.
honestduane

Funciona para mim quando mudei para json de xml.
Sike12

Na verdade, essa resposta chega à raiz do problema. O primeiro erro que recebi foi um erro de referência circular (tentando retornar JSON do controlador MVC). Quando mudei para um controlador herdado de API, comecei a receber este erro. Quando adicionei o código acima ao Global.asax, o erro foi embora.
Matthew Pitts de

43

no seu arquivo global.asax, no método Application_start () adicione esta linha:

GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;

Espero que isso te ajude!


3
O que é application_start e onde pode ser encontrado? E onde exatamente essa linha deve ser colocada?
Ciaran Gallagher

4
Desculpe, mas qual é o significado desta declaração?
Blaise

5
Linha adicionada a Global.asaxde Application_Start, mas sem alteração.
cheesus,

8
Isso ainda não funcionou para mim. No entanto, adicionei outra linha após a desta resposta e funcionou: GlobalConfiguration.Configuration.Formatters.Remove (GlobalConfiguration.Configuration.Formatters.XmlFormatter); Eu criei uma resposta mais completa abaixo
Zane

2
Essa resposta não deve ser aceita porque realmente remove o XmlSerializer em vez de abordar o problema da referência circular com o XmlSerializer.
Believe2014

29

Eu tenho o mesmo problema. E eu resolvi. Coloquei o construtor padrão na classe DTO.

Ex:

public class User
{
    public User()
    {
    }
}

Espero que funcione com você!


Obrigado pela sugestão, isso me ajudou com a resposta xml, mas alguém sabe por que precisa de um construtor padrão? Já temos os dados ...
Ilya Chernomordik

Acho que quando um objeto é serializado a partir da resposta, primeiro o construtor foi chamado para criar a instância do objeto, depois disso, o método set é usado para definir os dados para a instância do objeto. É meu palpite.
taynguyen

Esta deve ser a resposta escolhida, pois não faz nenhuma suposição sobre os tipos de retorno de que você precisa. Isso funcionará para XML e JSON. Obrigado por postar isso.
Allen Underwood

22

Coloque isso no construtor. Espero que isso resolva o problema:

    public MyController()
    {

        db.Configuration.ProxyCreationEnabled = false;
    }

Excelente solução. Eu preciso colocá-lo no construtor e funcionou.
InsParbo

Isso funcionou para mim em combinação com as configurações GlobalConfiguration. Mas por que isso funciona? Alguma explicação de como isso corrige o problema? E qual era realmente o problema?
Ciaran Gallagher,

Para entender o que são proxies de entidade: msdn.microsoft.com/en-us/library/jj592886(v=vs.113).aspx Para entender o que ProxyCreationEnabled é: stackoverflow.com/questions/7111109/…
Sadjad Khazaie

16

Eu encontrei duas soluções para isso. O primeiro e mais fácil de implementar é alterar qualquer IEnumerables, ICollections para um tipo de List. A WebAPI pode serializar esses objetos, mas não pode serializar os tipos de interface.

public class Store
{

  [StringLength(5)]
    public string Zip5 { get; set; }

    public virtual List<StoreReport> StoreReports { get; set; }  //use a list here
 }

A outra opção é não usar o serializador JSON nativo e executar essa substituição no método Register do WebApi Config:

        var json = config.Formatters.JsonFormatter;
        json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
        config.Formatters.Remove(config.Formatters.XmlFormatter);

1
Embora mudar para List tenha funcionado para mim, adicionar um construtor sem parâmetros também funcionou para mim e eu poderia continuar a retornar IEnumerable <Widget>
Mike Cheel

8

A solução é simples.

Após a consulta LINQ, adicione .ToList () (ou ToDictionary, se necessário).

Ele fará o carregamento mais rápido do que o carregamento lento dos dados


1
Alterar o tipo de retorno da ação para IENumerablee adicionar .TiList()ao retorno funcionou para mim.
Ricardo Souza

5

** este bug ocorre ao chamar a partir de request web api / wcf / ... do lado do cliente, mas como efeito colateral, você precisará incluir relações dependentes pela palavra-chave include. **

public CustomerPortalContext()
            : base("Name=CustomerPortalContext")
        {
            base.Configuration.ProxyCreationEnabled = false;
        }

4

Se você está trabalhando com EF, além de adicionar o código abaixo no Global.asax

            GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
        GlobalConfiguration.Configuration.Formatters.Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter);          

Não se esqueça de importar

using System.Data.Entity;

Então você pode devolver seus próprios modelos EF



3

Se você usar a API da Web com o Entity Framework, uma solução pode ser Falha ao serializar a resposta na API da Web com Json

Basicamente, você precisa criar um modelo correspondente a cada modelo de EF, isso remove as dependências entre as classes e permite a serialização fácil.

Código: (retirado do link referenciado)

Crie um UserModel

public class UserModel
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

Alterar meu método GetAll ()

public IEnumerable<UserModel> GetAll()
{
    using (Database db = new Database ())
    {
        List<UserModel> listOfUsers = new List<UserModel>();
        UserModel userModel = new UserModel();
        foreach(var user in db.Users)
        {
           userModel.FirstName = user.FirstName;
           userModel.LastName = user.LastName;
           listOfUsers.Add(userModel);
        }
        IEnumerable<UserModel> users = listOfUsers;

        return users;
    }
}

2

Default Entity 6 usa XML para apis, em seu projeto, encontre o arquivo "Global.asax" File e adicione esta linha:

GlobalConfiguration.Configuration.Formatters.Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter);

Esta linha remove o formatador XML.


Olá, Web API serializa a resposta em XML e JSON, se você adicionar o cabeçalho Content-Type: application / json, a resposta é em JSON, você precisa definir este cabeçalho, no navegador sempre você pode vê-lo no formato XML
Roberth Solís

1

mas se você encontrou esse problema com outras entidades / classes, você tem que criar um novo DTO para cada classe, e se você tiver muitos deles, você pode encontrar um problema, também acho que criar um DTO só para resolver esse problema não é a melhor maneira ...

Você tentou isso?

var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
json.SerializerSettings.PreserveReferencesHandling = 
Newtonsoft.Json.PreserveReferencesHandling.All;

Saudações


1

hmmm, Seguir pode ajudar.

Eu estava recebendo a mesma exceção e, no meu caso, estava passando a entidade poco real criada para o código de entidade primeiro. Como ele contém relação com outras entidades, acabei de criar a entidade viewmapper / dto em cima dela para retornar.

Funciona bem agora.

Entidade Poco:

public class Tag
{
public int Id{get;set;}
public string Title{get;set;}
public IList<Location> Locations{get;set;}
}

ViewMapper / Dto

public class TagResultsViewMapper
{
public int Id{get;set;}
public string Title{get;set;}
//just remove the following relationship 
//public IList<Location> Locations{get;set;}
}

0

Sua pergunta é bastante semelhante à minha. Você não deve retornar dados do banco de dados diretamente. Para isso, você deve criar o modelo e associar os dados que deseja mostrar.

No meu exemplo, há dados sobre o usuário que Json não conseguiu serializar, criei um userModel e, em minha API, retornei userModel em vez de User do banco de dados.

A lógica de converter ou associar dados entre User e UserModel deve estar na API.

Falha ao serializar a resposta na API da Web com Json


0

Este era o erro específico que eu estava obtendo da minha chamada de API da Web odata:

The 'ObjectContent`1' type failed to serialize the response 
body for content type 'application/json; odata.metadata=minimal'.

Eu finalmente descobri que minha classe dbContext tinha um nome de tabela mal formatado sendo atribuído em onModelCreating .. então o SqlClient estava morrendo procurando por uma tabela que não existia em meu banco de dados !!

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.