Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

json

c#

json.net

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. :)

like image 980
RottenCheese Avatar asked Dec 18 '17 22:12

RottenCheese


2 Answers

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>>();
like image 141
Brian Rogers Avatar answered Nov 07 '22 02:11

Brian Rogers


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.

like image 27
Alex Wiese Avatar answered Nov 07 '22 01:11

Alex Wiese