web-dev-qa-db-fra.com

Échec de la sérialisation de la réponse dans l'API Web avec Json

Je travaille avec ASP.NET MVC 5 Web Api. Je veux consulter tous mes utilisateurs.

J'ai écrit api/users et je reçois ceci:

"Le type 'ObjectContent`1' n'a pas pu sérialiser le corps de la réponse pour le type de contenu 'application/json; charset = utf-8'"

Dans WebApiConfig, j'ai déjà ajouté ces lignes:

HttpConfiguration config = new HttpConfiguration();
config.Formatters.XmlFormatter.SupportedMediaTypes.Remove(appXmlType);
config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore; 

Mais ça ne marche toujours pas.

Ma fonction pour les données de retour est la suivante:

public IEnumerable<User> GetAll()
{
    using (Database db = new Database())
    {
        return db.Users.ToList();
    }
}
100
CampDev

Lorsque vient le temps de renvoyer des données au consommateur à partir de Web Api (ou de tout autre service Web), je recommande vivement de ne pas restituer les entités provenant d'une base de données. Il est beaucoup plus fiable et maintenable d'utiliser des modèles dans lesquels vous avez le contrôle sur l'apparence des données et non sur la base de données. Ainsi, vous n'avez pas à vous soucier des formateurs dans WebApiConfig. Vous pouvez simplement créer un UserModel qui a des modèles enfants en tant que propriétés et supprimer les boucles de référence dans les objets de retour. Cela rend le sérialiseur beaucoup plus heureux.

En outre, il n'est généralement pas nécessaire de supprimer les formateurs ou les types de supports pris en charge si vous ne spécifiez que l'en-tête "Accepter" dans la demande. Jouer avec ce genre de choses peut parfois rendre les choses plus confuses.

Exemple:

public class UserModel {
    public string Name {get;set;}
    public string Age {get;set;}
    // Other properties here that do not reference another UserModel class.
}
71
jensendp

Si vous travaillez avec EF, en plus d'ajouter le code ci-dessous sur Global.asax

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

N'oubliez pas d'importer

using System.Data.Entity;

Ensuite, vous pouvez retourner vos propres modèles EF

Aussi simple que cela!

130
Lucas Roselli

La bonne réponse est un bon moyen d’aller, mais c’est exagéré de pouvoir le corriger à l’aide d’un paramètre de configuration.

Mieux vaut l'utiliser dans le constructeur de dbcontext

public DbContext() // dbcontext constructor
            : base("name=ConnectionStringNameFromWebConfig")
{
     this.Configuration.LazyLoadingEnabled = false;
     this.Configuration.ProxyCreationEnabled = false;
}

Erreur de l'API Web Asp.Net: le type 'ObjectContent`1' n'a pas pu sérialiser le corps de la réponse pour le type de contenu 'application/xml; charset = utf-8'

51
Md. Alim Ul Karim

Ajoutez ce code à global.asax ci-dessous sur Application_Start:

Mettre à jour de .Ignore à .Serialize. Ça doit marcher.

GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Serialize;
            GlobalConfiguration.Configuration.Formatters.Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter);
32
Bimal Das
public class UserController : ApiController
{

   Database db = new Database();

   // construction
   public UserController()
   {
      // Add the following code
      // problem will be solved
      db.Configuration.ProxyCreationEnabled = false;
   }

   public IEnumerable<User> GetAll()
    {
            return db.Users.ToList();
    }
}
10
Aykut

Je n'aime pas ce code:

foreach(var user in db.Users)

Comme alternative, on pourrait faire quelque chose comme ça, qui a fonctionné pour moi:

var listOfUsers = db.Users.Select(r => new UserModel
                         {
                             userModel.FirstName = r.FirstName;
                             userModel.LastName = r.LastName;

                         });

return listOfUsers.ToList();

Cependant, j'ai fini par utiliser la solution de Lucas Roselli.

Mise à jour: simplifiée en renvoyant un objet anonyme:

var listOfUsers = db.Users.Select(r => new 
                         {
                             FirstName = r.FirstName;
                             LastName = r.LastName;
                         });

return listOfUsers.ToList();
10

Je l'ai résolu en utilisant ce code dans le fichier WebApiConfig.cs

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

Ajouter ceci dans votre méthode Application_Start() de Global.asax devrait résoudre le problème

protected void Application_Start()
{
    GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings
        .ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
    GlobalConfiguration.Configuration.Formatters
        .Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter); 
// ...
}

METHODE 2: [Non recommandé]
Si vous travaillez avec EntityFramework, vous pouvez désactiver le proxy dans votre constructeur de classe DbContext. NOTE: ce code sera supprimé si vous mettez à jour le modèle

public class MyDbContext : DbContext
{
  public MyDbContext()
  {
    this.Configuration.ProxyCreationEnabled = false;
  }
}
6
Er Suman G

Il y a aussi ce scénario qui génère la même erreur:

Si le retour est une méthode List<dynamic> to web api

Exemple:

public HttpResponseMessage Get()
{
    var item = new List<dynamic> { new TestClass { Name = "Ale", Age = 30 } };

    return Request.CreateResponse(HttpStatusCode.OK, item);
}

public class TestClass
{
    public string Name { get; set; }
    public int Age { get; set; }
}

Donc, pour ce scénario, utilisez le [KnownTypeAttribute] dans la classe de retour (tous) comme ceci:

[KnownTypeAttribute(typeof(TestClass))]
public class TestClass
{
    public string Name { get; set; }
    public int Age { get; set; }
}

Cela fonctionne pour moi!

6
Alex

Mon préféré: ajoutez simplement le code ci-dessous à App_Start/WebApiConfig.cs. Cela retournera json au lieu de XML par défaut et empêchera également l'erreur que vous avez eue. Pas besoin de modifier Global.asax pour supprimer XmlFormatter etc.

Le type 'ObjectContent`1' n'a pas pu sérialiser le corps de la réponse pour le type de contenu 'application/xml; jeu de caractères = utf-8

config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));
4
Ogglas

Utilisez l'espace de noms suivant:

using System.Web.OData;

Au lieu de :

using System.Web.Http.OData;

Ça a fonctionné pour moi

2
Harish K

Solution qui a fonctionné pour moi:

  1. Utilisez [DataContract] pour la classe et les attributs [DataMember] pour chaque propriété à sérialiser. Cela suffit pour obtenir le résultat Json (par exemple de fiddler).

  2. Pour obtenir la sérialisation XML, écrivez dans Global.asax le code suivant:

    var xml = GlobalConfiguration.Configuration.Formatters.XmlFormatter; xml.UseXmlSerializer = true;

  3. Lisez cet article, cela m'a aidé à comprendre la sérialisation: https://www.asp.net/web-api/overview/formats-and-model-binding/json-and-xml-serialization
2
Lapenkov Vladimir

Utiliser AutoMapper ...

public IEnumerable<User> GetAll()
    {
        using (Database db = new Database())
        {
            var users = AutoMapper.Mapper.DynamicMap<List<User>>(db.Users);
            return users;
        }
    }
2
Proximo

Vous devrez définir le formateur de sérialiseur dans WebApiConfig.cs disponible dans le dossier App_Start, comme

Ajout de config.Formatters.Remove (config.Formatters.XmlFormatter); // qui vous fournira des données au format JSON

Ajout de config.Formatters.Remove (config.Formatters.JsonFormatter); // qui vous fournira des données au format XML

1
Yogesh Dangre

Pour ajouter à la réponse de jensendp:

Je voudrais transmettre l'entité à un modèle créé par l'utilisateur et utiliser les valeurs de cette entité pour définir les valeurs de votre modèle nouvellement créé. Par exemple:

public class UserInformation {
   public string Name { get; set; }
   public int Age { get; set; }

   public UserInformation(UserEntity user) {
      this.Name = user.name;
      this.Age = user.age;
   }
}

Puis changez votre type de retour en: IEnumerable<UserInformation>

1
Greg A

This is my error

J'ajoute essentiellement une ligne qu'ils sont

  • entités.Configuration.ProxyCreationEnabled = false;

à UsersController.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using UserDataAccess;

namespace SBPMS.Controllers
{
    public class UsersController : ApiController
    {


        public IEnumerable<User> Get() {
            using (SBPMSystemEntities entities = new SBPMSystemEntities()) {
                entities.Configuration.ProxyCreationEnabled = false;
                return entities.Users.ToList();
            }
        }
        public User Get(int id) {
            using (SBPMSystemEntities entities = new SBPMSystemEntities()) {
                entities.Configuration.ProxyCreationEnabled = false;
                return entities.Users.FirstOrDefault(e => e.user_ID == id);
            }
        }
    }
}

Here is my output:

1
GUL EDA AYDEMİR

Dans mon cas, j'ai eu un message d'erreur similaire:

Le type 'ObjectContent`1' n'a pas pu sérialiser le corps de la réponse pour le type de contenu 'application/xml; jeu de caractères = utf-8 '.

Mais quand j'y ai plongé plus profondément, le problème était:

Tapez 'name.SomeSubRootType' avec le nom du contrat de données 'SomeSubRootType: //schemas.datacontract.org/2004/07/WhatEverService' n'est pas attendu. Pensez à utiliser DataContractResolver si vous utilisez DataContractSerializer ou ajoutez des types non connus statiquement à la liste des types connus, par exemple, en utilisant l'attribut KnownTypeAttribute ou en les ajoutant à la liste des types connus transmis au sérialiseur.

La façon dont j'ai résolu en ajoutant KnownType.

[KnownType(typeof(SomeSubRootType))]
public partial class SomeRootStructureType

Ceci a été résolu inspiré de ceci réponse .

Référence: https://msdn.Microsoft.com/en-us/library/ms730167 (v = vs.100) .aspx

0

Dans mon cas, j'ai résolu de recréer la base de données. J'ai apporté des modifications à un modèle et en lançant Update-Database dans la console du gestionnaire de packages, l'erreur suivante s'est produite:

"L'instruction ALTER TABLE a été en conflit avec la contrainte FOREIGN KEY" FK_dbo.Activities_dbo.Projects_ProjectId ". Le conflit s'est produit dans la base de données" TrackEmAllContext-20190530144302 ", table" dbo.Projects ", colonne" Id "."

0
Manuel Sansone

Dans le cas où: Si vous ajoutez du code à WebApiConfig.cs ou Global.asax.cs ne fonctionne pas pour vous:

.ToList();

Ajoutez la fonction .ToList ().

J'ai essayé toutes les solutions mais les solutions suivantes ont fonctionné pour moi:

var allShops = context.shops.Where(s => s.city_id == id)**.ToList()**;
return allShops;

J'espère que ça aide.

0
Catalyst

Visual Studio 2017 ou 2019 est totalement irréfléchi, car Visual Studio exige lui-même que la sortie soit au format json , alors que le format par défaut de Visual Studio est " XmlFormat "(config.Formatters.XmlFormatter) .

Visual Studio doit le faire automatiquement au lieu de causer tant de problèmes aux développeurs.

Pour corriger ce problème, accédez au fichier WebApiConfig.cs et ajoutez

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

après " config.MapHttpAttributeRoutes (); " dans le registre (HttpConfiguration config) méthode. Cela permettrait à votre projet de générer une sortie JSON.

0
William Hou

Un autre cas où j'ai reçu cette erreur était lorsque ma requête de base de données a renvoyé une valeur null alors que mon type de modèle utilisateur/vue était défini sur non nullable. Par exemple, changer mon champ UserModel de int à int? résolu.

0
marshall

Cela se produit également lorsque le type de réponse n'est pas public! J'ai renvoyé une classe interne car j'ai utilisé Visual Studio pour générer le type.

internal class --> public class
0
Vanice

Ajouter la ligne ci-dessous

this.Configuration.ProxyCreationEnabled = false;

Deux façons d'utiliser ProxyCreationEnabled comme false.

  1. Ajoutez-le à l'intérieur de DBContext Constructeur

    public ProductEntities() : base("name=ProductEntities")
    {
        this.Configuration.ProxyCreationEnabled = false;
    }
    

OU

  1. Ajouter la ligne à l'intérieur de la méthode Get

    public IEnumerable<Brand_Details> Get()
    {
        using (ProductEntities obj = new ProductEntities())
        {
            this.Configuration.ProxyCreationEnabled = false;
            return obj.Brand_Details.ToList();
        }
    }
    
0
Sudipta Saha

Bien que toutes les réponses ci-dessus soient correctes, il peut être utile de vérifier le InnerException> ExceptionMessage .

Si elle indique quelque chose comme ceci "T , l'instance ObjectContext a été supprimée et ne peut plus être utilisée pour des opérations nécessitant une connexion. ". Cela pourrait être un problème en raison du comportement par défaut de l'EF.

En assignant LazyLoadingEnabled = false dans votre constructeur DbContext fera l'affaire.

public class MyDbContext : DbContext
{
  public MyDbContext()
  {
    this.Configuration.LazyLoadingEnabled = false;
  }
}

Pour plus d'informations sur le comportement de EF dans EagerLoading et LazyLoading, reportez-vous à ceci Article MSDN .

0
Bhramar

Utilisez [Serializable] pour la classe:

Exemple:

[Serializable]
public class UserModel {
    public string Name {get;set;}
    public string Age {get;set;}
}

Cela a fonctionné pour moi!

0
Msxmania