0

(EDIT: The JSON object is a dictionary, and can be deserialized natively into an object that implements IDictionary. See the duplicate question post.)

I am deserializing JSON data from an API and the format of the return data is a little odd (to me). I haven't seen it structured like this before, and I am hoping there is a way to deserialize this without building a custom converter.

{
    "1000" : {
        "id" : 1000, 
        "prop2" : "value2", 
        "prop3" : "value3"
    }, 
    "1001" : {
        "id" : 1001, 
        "prop2" : "value2", 
        "prop3" : "value3"
    }, 
    "XXXX" : {
        "id" : XXXX, 
        "prop2" : "value2", 
        "prop3" : "value3"
    }
}

As you can see from the example, rather than an array of objects, it is an object where the property name is the string value of the sub-object's ID. This is from HubSpot, and you can see the API doc here: https://developers.hubspot.com/docs/methods/contacts/get_batch_by_email

I've started down the road of creating a custom JSON converter which I am not very far along with yet, I just started testing. (It's not often that I need to do this, and I have to re-learn it each time.)

[JsonConverter(typeof(EmailContactConverter))]
internal class EmailContactListResponse
{
    public IEnumerable<ContactResponse> Contacts { get; set; }
}

class EmailContactConverter : JsonConverter
{
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException("Not implemented yet");
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null)
        {
            return string.Empty;
        }
        else if (reader.TokenType == JsonToken.String)
        {
            return serializer.Deserialize(reader, objectType);
        }
        else
        {
            JObject obj = JObject.Load(reader);
            var list = new List<ContactResponse>();
            return list;
        }
    }

    public override bool CanWrite
    {
        get { return false; }
    }

    public override bool CanConvert(Type objectType)
    {
        return false;
    }
}

Is there a way to represent this with built-in NewtonSoft JSON attributes or mapping? Or am I right to continue down the custom converter route?

jwatts1980
  • 7,254
  • 2
  • 28
  • 44
  • In what scenario would you not know what properties can your json object have? – JTinkers Feb 22 '19 at 20:39
  • @JCode I posted the link to the HubSpot API. The endpoint requires the email addresses of contacts, but the response uses the contact's internal ID's as the property name of the of the contact object. Like I said, it is odd to me that it would be structured this way. – jwatts1980 Feb 22 '19 at 20:41
  • If you're content to work with dynamic instances, there's always this: https://stackoverflow.com/a/8972079/2798367 – ne1410s Feb 22 '19 at 20:41
  • 3
    Deserialize into a `Dictionary` where `T` is your model class for the items. See the linked duplicate. – Brian Rogers Feb 22 '19 at 20:43
  • 1
    More likely it's a `Dictionary` – DavidG Feb 22 '19 at 20:43
  • You could use [linq-to-json](https://www.newtonsoft.com/json/help/html/QueryingLINQtoJSON.htm#QueryingLINQ) to construct the result. It might be easier than writing a custom converter. – Zohar Peled Feb 22 '19 at 20:43
  • 1
    @BrianRogers oh dang.. I didn't even think about this being a dictionary. Thanks! – jwatts1980 Feb 22 '19 at 20:45
  • That was it. I changed the class signature to `class EmailContactListResponse : IDictionary` and it deserialized perfectly. – jwatts1980 Feb 22 '19 at 21:15

0 Answers0