Deserialisasi JSON Object Array dengan Json.net

118

Saya mencoba menggunakan API yang menggunakan struktur contoh berikut untuk json yang dikembalikan

[
   {
      "customer":{
         "first_name":"Test",
         "last_name":"Account",
         "email":"[email protected]",
         "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":"[email protected]",
         "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 akan bekerja dengan baik dengan sesuatu seperti struktur berikut

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

Tapi saya tidak tahu bagaimana membuatnya senang dengan struktur yang disediakan.

Menggunakan JsonConvert.DeserializeObject (konten) default menghasilkan jumlah Pelanggan yang benar tetapi semua data adalah null.

Melakukan sesuatu yang CustomerList (di bawah) akan menghasilkan pengecualian "Tidak dapat menghilangkan derialisasi array JSON saat ini"

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

Pikiran?

Shawn C.
sumber
Apakah ini menjawab pertanyaan Anda? Deserialisasi JSON dengan C #
GetFookedWeeb

Jawaban:

187

Anda dapat membuat model baru untuk Deserialize Json Anda 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; }

    ...
}

Dan Anda dapat menghilangkan derialisasi json Anda dengan mudah:

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

Semoga membantu!

Dokumentasi: Serialisasi dan Deserialisasi JSON

Joffrey Kern
sumber
1
Terima kasih. Sudah terlalu memikirkan masalah. Saat Anda menjawab pertama, jawaban Anda diterima.
Shawn C.
2
JsonConvert.DeserializeObject <List <CustomerJson>> (json); Bekerja sempurna untuk input string.
Markel Mairs
DeserializeObject()lambat pada ponsel Android yang menjalankan ARM. Ada solusi yang lebih baik untuk kasus itu?
Tadej
1
Cobalah bernavigasi dengan JObjectJObject.Parse(json);
Joffrey Kern
47

Bagi yang tidak ingin membuat model apapun, gunakan kode berikut:

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

Catatan: Ini tidak berfungsi untuk string JSON Anda . Ini bukan solusi umum untuk struktur JSON apa pun.

Tyler Long
sumber
10
Ini adalah solusi yang buruk. Sebaliknya, jika Anda tidak ingin membuat model, gunakanvar result = JsonConvert.DeserializeObject<Tuple<string, string, string>>(content);
a11smiles
1
@ a11iles Tolong jelaskan mengapa ini adalah solusi yang buruk.
Tyler Long
2
Pertama, alokasi memori yang tidak perlu untuk berbagai jenis IEnumerableimplementasi (3 dibandingkan dengan Daftar <Tuple>). Kedua, solusi Anda menyiratkan dua kunci berbeda - 1 untuk setiap kamus. Apa yang terjadi jika beberapa pelanggan memiliki nama depan yang sama? Tidak akan ada perbedaan pada tombol-tombol tersebut. Solusi Anda tidak mempertimbangkan konflik ini.
a11smiles
2
@ a11iles setiap pelanggan adalah kamus terpisah. Jadi tidak akan ada masalah meskipun ada banyak pelanggan yang memiliki nama depan yang sama.
Tyler Long
1
@ a11iles Saya bertanya-tanya mengapa menurut Anda var result = JsonConvert.DeserializeObject<Tuple<string, string, string>>(content);akan berhasil. Rupanya itu tidak berhasil
Tyler Long
1

Menggunakan jawaban yang diterima, Anda harus mengakses setiap record dengan menggunakan Customers[i].customer, dan Anda memerlukan CustomerJsonkelas tambahan , yang sedikit mengganggu. Jika Anda tidak ingin melakukannya, Anda dapat menggunakan yang berikut ini:

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

Perhatikan bahwa saya menggunakan List<>, bukan Array. Sekarang buat kelas berikut:

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

Sedikit modifikasi pada apa yang disebutkan di atas. Format Json saya, yang memvalidasi adalah

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

         }
       }

Menggunakan respons AlexDev, saya melakukan Pendauran ini setiap anak, menciptakan pembaca darinya

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

}
JC_VA
sumber
0

Modifikasi lebih lanjut dari JC_VA, ambil apa yang dimilikinya, dan ganti MyModelConverter dengan ...

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

Ini harus bekerja untuk json

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

atau

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

keduanya akan diurai seolah-olah

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