Десеріалізація об’єктного масиву JSON за допомогою Json.net


118

Я намагаюся використовувати API, який використовує структуру наступного прикладу для повернутого json

[
   {
      "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 чудово співпрацює з такою структурою, як наступна структура

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

Але я не можу зрозуміти, як зробити це, щоб бути задоволеним наданою структурою.

Використання за замовчуванням JsonConvert.DeserializeObject (content) призводить до правильної кількості клієнтів, але всі дані є недійсними.

Здійснення чогось із списку клієнтів (нижче) призводить до винятку "Не вдається знеструмлювати поточний масив JSON"

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

Думки?


Чи відповідає це на ваше запитання? Десеріалізуйте JSON за допомогою C #
GetFookedWeeb

Відповіді:


187

Ви можете створити нову модель для десеріалізації вашого 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; }

    ...
}

І ви можете легко десаріалізувати свій json:

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

Сподіваюся, це допомагає!

Документація: Серіалізація та десеріалізація JSON


1
Дякую. Був над роздумом питання. Коли ви відповіли спочатку, ваша відповідь була прийнята.
Шон К.

2
JsonConvert.DeserializeObject <Список <CustomerJson>> (json); Працює ідеально для введення рядків.
Markel Mairs

DeserializeObject()повільно на андроїд-телефонах під керуванням ARM. Будь-яке краще рішення для цього випадку?
Тадей

1
Спробуйте перейти за допомогою JObjectJObject.Parse(json);
Joffrey Kern,

47

Для тих, хто не хоче створювати жодних моделей, використовуйте наступний код:

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

Примітка. Це не працює для вашого рядка JSON. Це не загальне рішення для будь-якої структури JSON.


10
Це жахливе рішення. Натомість, якщо ви не хотіли створювати моделі, використовуйтеvar result = JsonConvert.DeserializeObject<Tuple<string, string, string>>(content);
a11smiles

1
@ a11smiles Будь ласка, поясніть, чому це жахливе рішення.
Тайлер Лонг

2
По-перше, непотрібний розподіл пам'яті для різних типів IEnumerableреалізацій (3 порівняно зі списком <Tuple>). По-друге, ваше рішення передбачає дві чіткі клавіші - по 1 для кожного словника. Що станеться, якщо кілька клієнтів мають одне ім’я? Розмежування клавіш не було б. Ваше рішення не враховує цей конфлікт.
a11smiles

2
@ a11smiles кожен клієнт - це окремий словник. Тож не виникне жодних проблем, навіть якщо є кілька клієнтів, що мають одне ім’я.
Тайлер Лонг

1
@ a11smiles Мене цікавить, чому ти думав, що var result = JsonConvert.DeserializeObject<Tuple<string, string, string>>(content);буде працювати. Мабуть, це не працює
Тайлер Лонг

1

Використовуючи прийняту відповідь, ви маєте доступ до кожного запису за допомогою Customers[i].customer, і вам потрібен додатковий CustomerJsonклас, який трохи дратує. Якщо ви цього не хочете, ви можете скористатися наступним:

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

Зауважте, що я використовую a List<>, а не масив. Тепер створіть такий клас:

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();
}

1

Незначна зміна того, що було сказано вище. Мій формат Json, який підтверджує

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

         }
       }

Використовуючи відповідь AlexDev, я робив цю петлю кожної дитини, створюючи з неї читача

 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();

}

0

Подальша модифікація від JC_VA, візьміть те, що він має, і замініть MyModelConverter на ...

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();
}

Це повинно працювати для json, який є будь-яким

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

або

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

вони обидва в кінцевому підсумку будуть розібрані так, ніби вони були

myModelList{
 model: [{ ... object ... }]
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.