web-dev-qa-db-fra.com

Utilisation de JsonConvert.DeserializeObject pour désérialiser Json en classe C # POCO

Voici ma simple classe User POCO:

/// <summary>
/// The User class represents a Coderwall User.
/// </summary>
public class User
{
    /// <summary>
    /// A User's username. eg: "sergiotapia, mrkibbles, matumbo"
    /// </summary>
    public string Username { get; set; }

    /// <summary>
    /// A User's name. eg: "Sergio Tapia, John Cosack, Lucy McMillan"
    /// </summary>
    public string Name { get; set; }

    /// <summary>
    /// A User's location. eh: "Bolivia, USA, France, Italy"
    /// </summary>
    public string Location { get; set; }

    public int Endorsements { get; set; } //Todo.
    public string Team { get; set; } //Todo.

    /// <summary>
    /// A collection of the User's linked accounts.
    /// </summary>
    public List<Account> Accounts { get; set; }

    /// <summary>
    /// A collection of the User's awarded badges.
    /// </summary>
    public List<Badge> Badges { get; set; }

}

Et la méthode que j'utilise pour désérialiser une réponse JSON en un objet User (le présent appel JSON est ici ):

private User LoadUserFromJson(string response)
{
    var outObject = JsonConvert.DeserializeObject<User>(response);
    return outObject;
}

Cela déclenche une exception:

Impossible de désérialiser l'objet JSON actuel (par exemple, {"name": "value"}) en type 'System.Collections.Generic.List`1 [CoderwallDotNet.Api.Models.Account]' car le type nécessite un tableau JSON (par exemple, [1,2,3]) pour désérialiser correctement. 

Pour corriger cette erreur, changez le JSON en tableau JSON (par exemple, [1,2,3]) ou modifiez le type désérialisé pour qu’il s’agisse d’une valeur normale Type .NET (par exemple, pas de type primitif comme entier, ni de collection Comme un tableau ou une liste) pouvant être désérialisé à partir d'un fichier JSON. objet. JsonObjectAttribute peut également être ajouté au type pour le forcer désérialiser à partir d'un objet JSON. Chemin 'accounts.github', ligne 1, position 129.

N'ayant jamais travaillé avec cette méthode DeserializeObject auparavant, je suis un peu coincé ici.

Je me suis assuré que les noms de propriété de la classe POCO sont identiques à ceux de la réponse JSON. 

Que puis-je essayer de désérialiser JSON dans cette classe POCO?

51
Only Bolivian Here

Voici un exemple de travail. 

Les points clés sont:

  • Déclaration de Accounts
  • Utilisation de l'attribut JsonProperty

.

using (WebClient wc = new WebClient())
{
    var json = wc.DownloadString("http://coderwall.com/mdeiters.json");
    var user = JsonConvert.DeserializeObject<User>(json);
}

-

public class User
{
    /// <summary>
    /// A User's username. eg: "sergiotapia, mrkibbles, matumbo"
    /// </summary>
    [JsonProperty("username")]
    public string Username { get; set; }

    /// <summary>
    /// A User's name. eg: "Sergio Tapia, John Cosack, Lucy McMillan"
    /// </summary>
    [JsonProperty("name")]
    public string Name { get; set; }

    /// <summary>
    /// A User's location. eh: "Bolivia, USA, France, Italy"
    /// </summary>
    [JsonProperty("location")]
    public string Location { get; set; }

    [JsonProperty("endorsements")]
    public int Endorsements { get; set; } //Todo.

    [JsonProperty("team")]
    public string Team { get; set; } //Todo.

    /// <summary>
    /// A collection of the User's linked accounts.
    /// </summary>
    [JsonProperty("accounts")]
    public Account Accounts { get; set; }

    /// <summary>
    /// A collection of the User's awarded badges.
    /// </summary>
    [JsonProperty("badges")]
    public List<Badge> Badges { get; set; }
}

public class Account
{
    public string github;
}

public class Badge
{
    [JsonProperty("name")]
    public string Name;
    [JsonProperty("description")]
    public string Description;
    [JsonProperty("created")]
    public string Created;
    [JsonProperty("badge")]
    public string BadgeUrl;
}
85
L.B

Une autre approche, plus simple, de désérialisation d’une chaîne JSON à boîtier chameau en objet POCO à boîtier Pascal consiste à utiliser le paramètre CamelCasePropertyNamesContractResolver

Cela fait partie de l'espace de noms Newtonsoft.Json.Serialization. Cette approche suppose que la seule différence entre l'objet JSON et le POCO réside dans la casse des noms de propriété. Si les noms de propriété sont orthographiés différemment, vous devrez alors utiliser les attributs JsonProperty pour mapper les noms de propriété.

using Newtonsoft.Json; 
using Newtonsoft.Json.Serialization;

. . .

private User LoadUserFromJson(string response) 
{
    JsonSerializerSettings serSettings = new JsonSerializerSettings();
    serSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
    User outObject = JsonConvert.DeserializeObject<User>(jsonValue, serSettings);

    return outObject; 
}
4
John Iwasz

Vous pouvez créer une JsonConverter. Voir ici pour un exemple similaire à votre question.

4
SwDevMan81

La propriété des comptes est définie comme suit:

"accounts":{"github":"sergiotapia"}

Votre POCO dit ceci:

public List<Account> Accounts { get; set; }

Essayez d'utiliser ce Json:

"accounts":[{"github":"sergiotapia"}]

Un tableau d'éléments (qui va être mis en correspondance avec la liste) est toujours placé entre crochets.

Edit: Le compte Poco ressemblera à ceci:

class Account {
    public string github { get; set; }
}

et peut-être d'autres propriétés.

Edit 2: Pour ne pas avoir de tableau, utilisez la propriété comme suit:

public Account Accounts { get; set; }

avec quelque chose comme l'exemple de classe que j'ai posté dans la première édition.

3
Sascha
to fix this error either change the JSON to a JSON array (e.g. [1,2,3]) or change the
deserialized type so that it is a normal .NET type (e.g. not a primitive type like
integer, not a collection type like an array or List) that can be deserialized from a
JSON object.`

L’ensemble du message indique qu’il est possible de sérialiser en un objet List, mais que l’entrée doit être une liste JSON . Cela signifie que votre JSON doit contenir

"accounts" : [{<AccountObjectData}, {<AccountObjectData>}...],

Où les données AccountObject sont JSON représentant votre objet Account ou votre objet Badge

Ce qu'il semble être en train de devenir, c'est

"accounts":{"github":"sergiotapia"}

Où comptes est un objet JSON (indiqué par des accolades), et non un tableau d'objets JSON (les tableaux sont indiqués par des crochets), comme vous le souhaitez. Essayer

"accounts" : [{"github":"sergiotapia"}]
2
dmi_

Dans les lignes de la réponse acceptée, si vous avez un exemple de texte JSON, vous pouvez le brancher sur ce convertisseur , sélectionnez vos options et générez le code C #.

Si vous ne connaissez pas le type au moment de l'exécution, cette rubrique semble convenir.

désérialiser dynamiquement JSON en n'importe quel objet transmis. c #

1
Jim

Ce n'est pas exactement ce que j'avais en tête. Que faites-vous si vous avez un type générique à connaître uniquement au moment de l'exécution?

public MyDTO toObject() {
  try {
    var methodInfo = MethodBase.GetCurrentMethod();
    if (methodInfo.DeclaringType != null) {
      var fullName = methodInfo.DeclaringType.FullName + "." + this.dtoName;
      Type type = Type.GetType(fullName);
      if (type != null) {
        var obj = JsonConvert.DeserializeObject(payload);
      //var obj = JsonConvert.DeserializeObject<type.MemberType.GetType()>(payload);  // <--- type ?????
          ...
      }
    }

    // Example for Java..   Convert this to C#
    return JSONUtil.fromJSON(payload, Class.forName(dtoName, false, getClass().getClassLoader()));
  } catch (Exception ex) {
    throw new ReflectInsightException(MethodBase.GetCurrentMethod().Name, ex);
  }
}
0
Latency