143 votes

Désérialisation d'un tableau d'objets JSON avec Json.net

J'essaie d'utiliser une API qui utilise l'exemple de structure suivant pour son json retourné.

[
   {
      "customer":{
         "first_name":"Test",
         "last_name":"Account",
         "email":"test1@example.com",
         "organization":"",
         "reference":null,
         "id":3545134,
         "created_at":"2013-08-06T15:51:15-04:00",
         "updated_at":"2013-08-06T15:51:15-04:00",
         "address":"",
         "address_2":"",
         "city":"",
         "state":"",
         "zip":"",
         "country":"",
         "phone":""
      }
   },
   {
      "customer":{
         "first_name":"Test",
         "last_name":"Account2",
         "email":"test2@example.com",
         "organization":"",
         "reference":null,
         "id":3570462,
         "created_at":"2013-08-12T11:54:58-04:00",
         "updated_at":"2013-08-12T11:54:58-04:00",
         "address":"",
         "address_2":"",
         "city":"",
         "state":"",
         "zip":"",
         "country":"",
         "phone":""
      }
   }
]

JSON.net fonctionnerait très bien avec quelque chose comme la structure suivante

{
    "customer": {
        ["field1" : "value", etc...],
        ["field1" : "value", etc...],
    }
}

Mais je n'arrive pas à trouver comment faire pour qu'il soit satisfait de la structure fournie.

L'utilisation de la fonction par défaut JsonConvert.DeserializeObject(content) donne le nombre correct de clients mais toutes les données sont nulles.

Faire quelque chose avec une liste de clients (ci-dessous) donne lieu à une exception "Impossible de désérialiser le tableau JSON actuel".

public class CustomerList
{
    public List<Customer> customer { get; set; }
}

Qu'en pensez-vous ?

213voto

Joffrey Kern Points 2171

Vous pouvez créer un nouveau modèle pour désérialiser votre JSON. CustomerJson :

    public class CustomerJson
    {
        [JsonProperty("customer")]
        public Customer Customer { get; set; }
    }

    public class Customer
    {
        [JsonProperty("first_name")]
        public string Firstname { get; set; }

        [JsonProperty("last_name")]
        public string Lastname { get; set; }

        ...
    }

Et vous pouvez désérialiser votre JSON facilement :

JsonConvert.DeserializeObject<List<CustomerJson>>(json);

Documentation : Sérialisation et désérialisation de JSON

49voto

Tyler Long Points 1216

Pour ceux qui ne veulent pas créer de modèles, utilisez le code suivant :

var result = JsonConvert.DeserializeObject<
  List<Dictionary<string, 
    Dictionary<string, string>>>>(content);

Note : Cela ne fonctionne pas pour su Chaîne JSON. Cette chaîne est pas une solution générale pour toute structure JSON.

3voto

AlexDev Points 1238

En utilisant la réponse acceptée, vous devez accéder à chaque enregistrement en utilisant Customers[i].customer et vous avez besoin d'un supplément CustomerJson ce qui est un peu ennuyeux. Si vous ne voulez pas faire cela, vous pouvez utiliser ce qui suit :

public class CustomerList
{
    [JsonConverter(typeof(MyListConverter))]
    public List<Customer> customer { get; set; }
}

Notez que j'utilise un List<> et non un tableau. Créez maintenant la classe suivante :

class MyListConverter : JsonConverter
{
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var token = JToken.Load(reader);
        var list = Activator.CreateInstance(objectType) as System.Collections.IList;
        var itemType = objectType.GenericTypeArguments[0];
        foreach (var child in token.Values())
        {
            var childToken = child.Children().First();
            var newObject = Activator.CreateInstance(itemType);
            serializer.Populate(childToken.CreateReader(), newObject);
            list.Add(newObject);
        }
        return list;
    }

    public override bool CanConvert(Type objectType)
    {
        return objectType.IsGenericType && (objectType.GetGenericTypeDefinition() == typeof(List<>));
    }
    public override bool CanWrite => false;
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) => throw new NotImplementedException();
}

1voto

JC_VA Points 17

Légère modification de ce qui a été dit ci-dessus. Mon format Json, qui valide était

{
    mycollection:{[
           {   
               property0:value,
               property1:value,
             },
             {   
               property0:value,
               property1:value,
             }
           ]

         }
       }

En utilisant la réponse d'AlexDev, j'ai fait ceci Boucler chaque enfant, créer un lecteur à partir de lui

 public partial class myModel
{
    public static List<myModel> FromJson(string json) => JsonConvert.DeserializeObject<myModelList>(json, Converter.Settings).model;
}

 public class myModelList {
    [JsonConverter(typeof(myModelConverter))]
    public List<myModel> model { get; set; }

}

class myModelConverter : JsonConverter
{
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var token = JToken.Load(reader);
        var list = Activator.CreateInstance(objectType) as System.Collections.IList;
        var itemType = objectType.GenericTypeArguments[0];
        foreach (var child in token.Children())  //mod here
        {
            var newObject = Activator.CreateInstance(itemType);
            serializer.Populate(child.CreateReader(), newObject); //mod here
            list.Add(newObject);
        }
        return list;
    }

    public override bool CanConvert(Type objectType)
    {
        return objectType.IsGenericType && (objectType.GetGenericTypeDefinition() == typeof(List<>));
    }
    public override bool CanWrite => false;
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) => throw new NotImplementedException();

}

0voto

andmar8 Points 331

Nouvelle modification de JC_VA, prenez ce qu'il a, et remplacez le MyModelConverter par...

public class MyModelConverter : JsonConverter
{
    //objectType is the type as specified for List<myModel> (i.e. myModel)
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var token = JToken.Load(reader); //json from myModelList > model
        var list = Activator.CreateInstance(objectType) as System.Collections.IList; // new list to return
        var itemType = objectType.GenericTypeArguments[0]; // type of the list (myModel)
        if (token.Type.ToString() == "Object") //Object
        {
            var child = token.Children();
            var newObject = Activator.CreateInstance(itemType);
            serializer.Populate(token.CreateReader(), newObject);
            list.Add(newObject);
        }
        else //Array
        {
            foreach (var child in token.Children())
            {
                var newObject = Activator.CreateInstance(itemType);
                serializer.Populate(child.CreateReader(), newObject);
                list.Add(newObject);
            }
        }
        return list;

    }

    public override bool CanConvert(Type objectType)
    {
        return objectType.IsGenericType && (objectType.GetGenericTypeDefinition() == typeof(List<>));
    }
    public override bool CanWrite => false;
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) => throw new NotImplementedException();
}

Cela devrait fonctionner pour les fichiers json qui sont soit

myModelList{
 model: [{ ... object ... }]
}

ou

myModelList{
 model: { ... object ... }
}

ils seront tous deux analysés comme s'il s'agissait de

myModelList{
 model: [{ ... object ... }]
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X