-1

I am having trouble deserializing JSON received from HubSpot ContactList API.

I am using Restsharp and NewtonSoft, and I'm having real struggles understanding how to correctly define the required classes in order to deserialize the JSON string, which is below:

  "contacts": [
    {
      "vid": 2251,
      "portal-id": 5532227,
      "is-contact": true,
      "profile-url": "https://app.hubspot.com/contacts/5532227/contact/2251",
      "properties": {
        "firstname": {
          "value": "Carl"
        },
        "lastmodifieddate": {
          "value": "1554898386040"
        },
        "company": {
          "value": "Cygnus Project"
        },
        "lastname": {
          "value": "Swann"
        }
      },
      "form-submissions": [],
      "identity-profiles": [
        {
          "vid": 2251,
          "saved-at-timestamp": 1553635648634,
          "deleted-changed-timestamp": 0,
          "identities": [
            {
              "type": "EMAIL",
              "value": "cswann@cygnus.co.uk",
              "timestamp": 1553635648591,
              "is-primary": true
            },
            {
              "type": "LEAD_GUID",
              "value": "e2345",
              "timestamp": 1553635648630
            }
          ]
        }
      ],
      "merge-audits": []
    },
    {
      "vid": 2301,
      "portal-id": 5532227,
      "is-contact": true,
      "profile-url": "https://app.hubspot.com/contacts/5532227/contact/2301",
      "properties": {
        "firstname": {
          "value": "Carlos"
        },
        "lastmodifieddate": {
          "value": "1554886333954"
        },
        "company": {
          "value": "Khaos Control"
        },
        "lastname": {
          "value": "Swannington"
        }
      },
      "identity-profiles": [
        {
          "vid": 2301,
          "saved-at-timestamp": 1553635648733,
          "deleted-changed-timestamp": 0,
          "identities": [
            {
              "type": "EMAIL",
              "value": "cswann@khaoscontrol.com",
              "timestamp": 1553635648578,
              "is-primary": true
            },
            {
              "type": "LEAD_GUID",
              "value": "c7f403ba",
              "timestamp": 1553635648729
            }
          ]
        }
      ],
      "merge-audits": []
    }
  ],
  "has-more": false,
  "vid-offset": 2401
}

If I simply request the vid, I correctly get 2 vid's back. It's when I try to do the properties and that i get a fail.

Please help

Swanne
  • 88
  • 9
  • 2
    Try to get class structure for your json from http://json2csharp.com/ – er-sho Apr 16 '19 at 07:38
  • 1
    Possible duplicate of [Deserialize JSON with C#](https://stackoverflow.com/questions/7895105/deserialize-json-with-c-sharp) – Liam Apr 16 '19 at 07:38
  • I won't flag as a duplicate of this (or the above), but have a read of this... https://stackoverflow.com/questions/3142495/deserialize-json-into-c-sharp-dynamic-object You can deserialize JSON into a `dynamic` object so you don't need to define a class. – Reinstate Monica Cellio Apr 16 '19 at 07:39
  • @ER , for a grinder of Json Csv dupe. I found you hard on that one. Json2Csharp limit is those dictionary string, string thingy. And that the issue here. – xdtTransform Apr 16 '19 at 07:41
  • @Swanne, building an [MCVE], you can reduce your json to the only part that cause the issue the `properties`. From that point it will be clearer what you issue is. You will then have to determine the way you want to solve it. I will go for droping the value and store the data in a dictionary this way you have the property only once and their value store as text till you know what the type should be. – xdtTransform Apr 16 '19 at 07:45
  • @Swanne, Did you tried my answer below? Let me know if you faced any problem. – er-sho Apr 16 '19 at 17:49

2 Answers2

2

Lets reduce the Json to the minimum to reproduce your error :

{
    "vid": 2301,
    "portal-id": 5532227,
    "is-contact": true,
    "profile-url": "https://app.hubspot.com/contacts/5532227/contact/2301",
    "properties": {
        "firstname": {
            "value": "Carlos"
        },
        "lastmodifieddate": {
            "value": "1554886333954"
        },
        "company": {
            "value": "Khaos Control"
        },
        "lastname": {
            "value": "Swannington"
        }
    }
}

And the appropriate class ContactListAPI_Result:

public partial class ContactListAPI_Result
{
    [JsonProperty("vid")]
    public long Vid { get; set; }

    [JsonProperty("portal-id")]
    public long PortalId { get; set; }

    [JsonProperty("is-contact")]
    public bool IsContact { get; set; }

    [JsonProperty("profile-url")]
    public Uri ProfileUrl { get; set; }

    [JsonProperty("properties")]
    public Dictionary<string, Dictionary<string, string>> Properties { get; set; }
}

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

public static void toto()
{
    string input = @"    {
    ""vid"": 2301,
    ""portal-id"": 5532227,
    ""is-contact"": true,
    ""profile-url"": ""https://app.hubspot.com/contacts/5532227/contact/2301"",
    ""properties"": {
        ""firstname"": {
            ""value"": ""Carlos""
        },
        ""lastmodifieddate"": {
            ""value"": ""1554886333954""
        },
        ""company"": {
            ""value"": ""Khaos Control""
        },
        ""lastname"": {
            ""value"": ""Swannington""
        }
    }
}";

    var foo = ContactListAPI_Result.FromJson(input);
}

But the Value of one property will be burrow in the sub dictionary, we can the project the object in a more usefull one :

public partial class ItemDTO
{
    public long Vid { get; set; }
    public long PortalId { get; set; }
    public bool IsContact { get; set; }
    public Uri ProfileUrl { get; set; }
    public Dictionary<string, string> Properties { get; set; }
}

Adding the projection to the Class:

public ItemDTO ToDTO()
{
    return new ItemDTO
    {
        Vid = Vid,
        PortalId = PortalId,
        IsContact = IsContact,
        ProfileUrl = ProfileUrl,
        Properties = 
            Properties.ToDictionary(
                p => p.Key, 
                p => p.Value["value"]
            )
    };
}

Usage :

var result = foo.ToDTO();

Live Demo

xdtTransform
  • 1,986
  • 14
  • 34
  • Will add a online Demo when I get back from my break. If you have any question. – xdtTransform Apr 16 '19 at 08:12
  • Thank you so much for taking the time to assist. An online demo will most certainly be very useful. I look forward to it. Thank you again – Swanne Apr 16 '19 at 13:33
  • @Swanne, [live demo](https://dotnetfiddle.net/6wNvor). Basically copy pasted from the answer directly – xdtTransform Apr 16 '19 at 15:24
  • Thank you. I am getting some strange errors. My project is a winforms project and the error messages seem to point to that. Any idea? – Swanne Apr 16 '19 at 16:31
  • @Swanne, That's a really vague description. It's like Calling a doctor just saying the word "pain". Do you have any indication of where? What kind of error? Winform/Console/WPF will all behave. – xdtTransform Apr 17 '19 at 06:25
  • If I had to make a guess, I will say in `ContactListAPI_Result FromJson` remove the `=>` add a `return` and don't forget the `{}`. Like in the live demo. – xdtTransform Apr 17 '19 at 06:27
  • Hey @xdtTransform. Thank you very much for all of your help. I really appreciate it. I used your code to successfully achieve what I set out to do. Thank you again – Swanne Apr 18 '19 at 20:56
0

Creating and managing class structure for big and nested key/value pair json is tedious task

So one approach is to use JToken instead.

You can simply parse your JSON to JToken and by querying parsed object, you will easily read the data that you want without creating class structure for your json

From your post it seems you need to retrieve vid and properties from your json so try below code,

string json = "Your json here";

JToken jToken = JToken.Parse(json);

var result = jToken["contacts"].ToObject<JArray>()
    .Select(x => new
    {
        vid = Convert.ToInt32(x["vid"]),
        properties = x["properties"].ToObject<Dictionary<string, JToken>>()
                                    .Select(y => new
                                    {
                                       Key = y.Key,
                                       Value = y.Value["value"].ToString()
                                    }).ToList()
    }).ToList();


//-----------Print the result to console------------

foreach (var item in result)
{
    Console.WriteLine(item.vid);

    foreach (var prop in item.properties)
    {
        Console.WriteLine(prop.Key + " - " + prop.Value);
    }

    Console.WriteLine();
}

Output:

enter image description here

er-sho
  • 9,581
  • 2
  • 13
  • 26