Home > Software engineering >  Deserialize JSON into custom c# object list
Deserialize JSON into custom c# object list

Time:10-16

From the api call:

 var httpClient = new HttpClient();
 var uri = "https://api.postcodes.io/postcodes/";
 var response = await httpClient.PostAsync(uri, data);
 string result = response.Content.ReadAsStringAsync().Result;
 var list = JsonConvert.DeserializeObject<GeoDataList>(result);

with two custom classes:

  [Serializable]
    public class GeoData
{
    [JsonProperty("postcode")]
    public string postcode { get; set; }

    [JsonProperty("longitude")]
    public string longitude { get; set; }
    [JsonProperty("latitude")]
    public string latitude { get; set; }
}

    public class GeoDataList
    {
        [JsonProperty("result")]
        public List<GeoData> geoDatas { get; set; }
    }

The result contains this json-string:

{
  "status": 200,
  "result": [{
    "query": "OX49 5NU",
    "result": {
      "postcode": "OX49 5NU",
      "longitude": -1.069876,
      "latitude": 51.6562
    }
  }, {
    "query": "M32 0JG",
    "result": {
      "postcode": "M32 0JG",
      "longitude": -2.302836,
      "latitude": 53.455654
    }
  }, {
    "query": "NE30 1DP",
    "result": {
      "postcode": "NE30 1DP",
      "longitude": -1.439269,
      "latitude": 55.011303,
    }
  }]
}

The list contains 3 empty objects. postcode, longitude, and latitude are null. How do I populate the inner objects (GeoData)?

Kind regard /Rudy

CodePudding user response:

So, when we have to work with JSON and we really don't want to grunt all this out by hand, because it's tedious and liable to error, we go to http://quicktype.io (or json2csharp, or some similar site) and we paste our JSON in there..

We fix up any syntax errors in the json (quicktype shows a red bar in the json-paste window), like the trailing comma on the last result latitude, and we get this bunch of classes generated by QuickType:

// <auto-generated />
//
// To parse this JSON data, add NuGet 'Newtonsoft.Json' then do:
//
//    using SomeNamespace;
//
//    var root = Root.FromJson(jsonString);

namespace SomeNamespace
{
    using System;
    using System.Collections.Generic;

    using System.Globalization;
    using Newtonsoft.Json;
    using Newtonsoft.Json.Converters;

    public partial class Root
    {
        [JsonProperty("status")]
        public long Status { get; set; }

        [JsonProperty("result")]
        public ResultElement[] Result { get; set; }
    }

    public partial class ResultElement
    {
        [JsonProperty("query")]
        public string Query { get; set; }

        [JsonProperty("result")]
        public ResultResult Result { get; set; }
    }

    public partial class ResultResult
    {
        [JsonProperty("postcode")]
        public string Postcode { get; set; }

        [JsonProperty("longitude")]
        public double Longitude { get; set; }

        [JsonProperty("latitude")]
        public double Latitude { get; set; }
    }

    public partial class Root
    {
        public static Root FromJson(string json) => JsonConvert.DeserializeObject<Root>(json, SomeNamespace.Converter.Settings);
    }

    public static class Serialize
    {
        public static string ToJson(this Root self) => JsonConvert.SerializeObject(self, SomeNamespace.Converter.Settings);
    }

    internal static class Converter
    {
        public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
        {
            MetadataPropertyHandling = MetadataPropertyHandling.Ignore,
            DateParseHandling = DateParseHandling.None,
            Converters =
            {
                new IsoDateTimeConverter { DateTimeStyles = DateTimeStyles.AssumeUniversal }
            },
        };
    }
}

And the comment at the top tells us how to use it:

var root = Root.FromJson(jsonString);

And then if you just want the inner result objects you could:

root.Result.Select(r => r.Result).ToList()

If you don't like the class names that QT has picked, you can refactor/rename them in VS - the json will remain parsable because it also added all the [Jsonproeprty] attributes for you with the names as per the JSON so the C# props can be anything you like

QT is Newtonsoft oriented; if you want to use the generated classes with System.Text.Json you just have to adjust the attribute names with find/replace and a couple of other bits of tidy up

I have zero affiliation with QT

  • Related