no se pudo serializar la respuesta en la API web

86

Estaba trabajando en la API web ASP.NET MVC, tengo este error:

El tipo 'ObjectContent`1' no pudo serializar el cuerpo de la respuesta para el tipo de contenido 'application / xml; charset = utf-8 '.

Mi controlador es:

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

¿Por qué recibo este error?

Tamal kanti Dey
fuente
6
La excepción que está viendo es una excepción general, que puede deberse a varios factores. Verifique la InnerExceptionpropiedad de la excepción de serialización para averiguar qué causó exactamente que fallara la serialización.
Nombre
¿Puede compartir el código para su tipo de empleado? Podría ser porque el tipo Empleado no es serializable ...
Maggie Ying
También eche un vistazo a este stackoverflow.com/questions/8173524/…
sttaq

Respuestas:

121

Para mí, esto fue un problema con las referencias circulares.

La respuesta aceptada no me funcionó porque solo cambia el comportamiento del formateador JSON, pero estaba obteniendo XML cuando llamé al servicio desde el navegador.

Para solucionar esto, apagué XML y obligué a que solo se devolviera JSON.

En el archivo Global.asax, coloque las siguientes líneas en la parte superior de su método Application_Start:

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

Ahora solo se devolverán los resultados JSON. Si necesita resultados XML, deberá encontrar una solución diferente.

Zane
fuente
funcionó para mí. pero la cosa es que estoy usando POSTMAN. es una extensión de Chrome. cuando publico datos con POSTMAN funciona bien. pero cuando uso restsharp me da este error. de todos modos, su solución solucionó mi problema
ArgeKumandan
Esta respuesta no proporciona una solución para usar xml, y eso es lo que pidió.
honestduane
Funciona para mí cuando encendí json desde xml.
Sike12
En realidad, esta respuesta llega a la raíz del problema. El primer error que recibí fue un error de referencia circular (tratando de devolver JSON desde el controlador MVC). Cuando cambié a un controlador heredado de API, comencé a recibir este error. Cuando agregué el código anterior a Global.asax, el error desapareció.
Matthew Pitts
43

en su archivo global.asax, en el método Application_start () agregue esta línea:

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

¡Espero que eso te ayude!

Julito Avellaneda
fuente
3
¿Qué es application_start y dónde se puede encontrar? ¿Y dónde exactamente debería colocarse esta línea?
Ciaran Gallagher
4
Lo siento, pero ¿cuál es el significado de esta declaración?
Blaise
5
Línea agregada a Global.asax's Application_Start, pero sin cambios.
Cheesus
8
Esto todavía no funcionó para mí. Sin embargo, agregué otra línea después de la de esta respuesta y funcionó: GlobalConfiguration.Configuration.Formatters.Remove (GlobalConfiguration.Configuration.Formatters.XmlFormatter); He creado una respuesta más completa a continuación
Zane
2
Esta respuesta no debe aceptarse porque de hecho elimina XmlSerializer en lugar de abordar el problema de la referencia circular con XmlSerializer.
Believe2014
29

Tengo el mismo problema. Y lo resolví. Pongo el constructor predeterminado en la clase DTO.

Ex:

public class User
{
    public User()
    {
    }
}

¡Espero que funcione contigo!

taynguyen
fuente
Gracias por la sugerencia, esto me ayudó con la respuesta xml, pero ¿alguien sabe por qué necesita un constructor predeterminado? Ya tenemos los datos ...
Ilya Chernomordik
Creo que cuando un objeto se serializa a partir de la respuesta, primero se llamó al constructor para crear una instancia del objeto, después de eso, el método set se usa para configurar los datos en la instancia del objeto. Esa es mi suposición.
taynguyen
En realidad, esta debería ser la respuesta elegida, ya que no hace ninguna suposición sobre los tipos de devolución que necesita. Esto funcionará tanto para XML como para JSON. Gracias por publicar esto.
Allen Underwood
22

Pon esto en constructor. Espero que esto resuelva el problema:

    public MyController()
    {

        db.Configuration.ProxyCreationEnabled = false;
    }
Sadjad Khazaie
fuente
Excelente solucion. Necesito ponerlo en el constructor y funcionó.
InsParbo
Esto funcionó para mí en combinación con la configuración de GlobalConfiguration. Pero, ¿por qué funciona esto? ¿Alguna explicación de cómo esto soluciona el problema? ¿Y cuál era realmente el problema?
Ciaran Gallagher
Para comprender qué son los proxies de entidad: msdn.microsoft.com/en-us/library/jj592886(v=vs.113).aspx Para comprender qué es ProxyCreationEnabled: stackoverflow.com/questions/7111109/…
Sadjad Khazaie
16

Encontré dos soluciones para esto. La primera y más fácil de implementar es cambiar cualquier IEnumerables, ICollections a un tipo de Lista. WebAPI puede serializar estos objetos, sin embargo, no puede serializar tipos de interfaz.

public class Store
{

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

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

La otra opción es no usar el serializador JSON nativo y ejecutar esta anulación en el método Register de WebApi Config:

        var json = config.Formatters.JsonFormatter;
        json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
        config.Formatters.Remove(config.Formatters.XmlFormatter);
Ray Suelzer
fuente
1
Aunque cambiar a List funcionó para mí, agregar un constructor sin parámetros también funcionó para mí y pude continuar devolviendo IEnumerable <Widget>
Mike Cheel
8

La solución es simple.

Después de la consulta LINQ, agregue .ToList () (o ToDictionary si es necesario).

Hará una carga ansiosa que una carga diferida de los datos

om471987
fuente
1
Cambiar el tipo de retorno de acción ay IENumerableagregar .TiList()al retorno funcionó para mí.
Ricardo Souza
5

** este error ocurre cuando se llama desde la solicitud web api / wcf / ... desde el lado del cliente, pero como efecto secundario, deberá incluir las relaciones dependientes mediante la palabra clave include. **

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

Si está trabajando con EF, además de agregar el siguiente código en Global.asax

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

No olvides importar

using System.Data.Entity;

Entonces puede devolver sus propios modelos EF

Lucas Roselli
fuente
3

Si usa la API web con Entity Framework, es posible que una solución no pueda serializar la respuesta en la API web con Json

Básicamente, necesita crear un modelo correspondiente a cada modelo EF, esto elimina las dependencias entre clases y permite una fácil serialización.

Código: (tomado del enlace de referencia)

Crear un modelo de usuario

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

Cambiar mi 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;
    }
}
Tung Nguyen
fuente
2

La Entidad 6 predeterminada usa XML para apis, en su proyecto, busque el archivo "Global.asax" File y agregue esta línea:

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

Esta línea elimina el formateador XML.

Roberth Solís
fuente
Hola, Web API serializa la respuesta en XML y JSON, si agregas encabezado Content-Type: application / json, la respuesta está en JSON, necesitas definir este encabezado, en el navegador siempre puedes verlo como formato XML
Roberth Solís
1

pero si encontraste este problema con otras entidades / clases, tienes que crear un nuevo DTO para cada clase, y si tienes muchos de ellos, puedes encontrar un problema, también creo que crear un DTO solo para resolver este problema no es la mejor manera ...

¿Intentaste esto?

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

Saludos

Julito Avellaneda
fuente
1

hmmm, lo siguiente puede ayudar.

Recibía la misma excepción y, en mi caso, pasaba primero la entidad poco real creada para el código de entidad. Dado que contiene relación con otras entidades, acabo de crear la entidad viewmapper / dto encima para regresar.

Funciona bien ahora.

Entidad 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;}
}
aamir sajjad
fuente
0

Tu pregunta es bastante similar a la mía. No debe devolver datos de la base de datos directamente. Para ello, debe crear el modelo y asociar los datos que desea mostrar.

En mi ejemplo, hay datos sobre User que Json no pudo serializar, tuve que crear un userModel y, en mi API, devuelvo userModel en lugar de User from database.

La lógica de convertir o asociar datos entre User y UserModel debe estar en API.

No se pudo serializar la respuesta en la API web con Json

CampDev
fuente
0

Este era el error específico que recibía de mi llamada a la API web de odata:

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

Finalmente descubrí que mi clase dbContext tenía un nombre de tabla mal formateado que se estaba asignando en onModelCreating ... ¡¡así que SqlClient se estaba muriendo buscando una tabla que no existía en mi base de datos !!

bkwdesign
fuente