简体   繁体   中英

Best way to deserialize a nested list in a json - C#

I got this Json:

{
    "CountriesAndCities": [
        {
            "CountryId": 2,
            "CountryName": "Chile",
            "CountryISOA3": "CHL",
            "Cities": [
                {
                    "CityId": 26,
                    "CityName": "Gran Santiago",
                    "Country": null
                },
                {
                    "CityId": 27,
                    "CityName": "Gran Concepción",
                    "Country": null
                }
            ]
        }
    ]
}

As you can see, it's a lists of objects, and those objects have another list nested.

I've got these models:

public class City
    {
        public int CityId { get; set; }
        public string CityName { get; set; }
        public Country Country { get; set; }
    }

    public class Country
    {
        public int CountryId { get; set; }
        public string CountryName { get; set; }
        public string CountryISOA3 { get; set; }
        public ICollection<City> Cities { get; set; }
    }

Right now, this does the trick:

public ICollection<Country> Countries { get; set; }

        public RegionViewModel()
        {
            // Pidiendo las ciudades al backend.
            S3EWebApi webApi = new S3EWebApi();
            HttpResponseMessage response = webApi.Get("/api/Benefits/GetCountriesAndCities");
            string jsonResponseString = response.Content.ReadAsStringAsync().Result;
            JObject jsonResponse = JsonConvert.DeserializeObject<JObject>(jsonResponseString);

            string countriesAndCitiesJSon = jsonResponse["CountriesAndCities"].ToString();
            Countries = JsonConvert.DeserializeObject<List<Country>>(countriesAndCitiesJSon);
        }

But I don't know, I think that's way too far from elegant. Is there a better approach to it? Thanks. :)

Make a wrapper class for the response.

public class CountriesAndCitiesResponse
{
    public List<Country> CountriesAndCities { get; set; }
}

Then use it like so:

public RegionViewModel()
{
    // Pidiendo las ciudades al backend.
    S3EWebApi webApi = new S3EWebApi();
    HttpResponseMessage response = webApi.Get("/api/Benefits/GetCountriesAndCities");
    string jsonResponseString = response.Content.ReadAsStringAsync().Result;
    CountriesAndCitiesResponse response = JsonConvert.DeserializeObject<CountriesAndCitiesResponse>(jsonResponseString);

    Countries = response.CountriesAndCities;
}

Also you should re-think calling an async method in a constructor (it could lead to deadlocks). You might consider having the call in an async Task Load() method instead and calling that after calling the constructor.

Generally speaking you should never need to deserialize twice. The simplest solution is to make a class to represent the outermost part of the JSON and then deserialize into that as shown in @Alex Wiese's answer .

If you want to deserialize without a root class then you can use the ToObject<T>() method after you have deserialized into the JObject .

JObject jsonResponse = JsonConvert.DeserializeObject<JObject>(jsonResponseString);
Countries = jsonResponse["CountriesAndCities"].ToObject<List<Country>>();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM