2
votes

Same question as Deserializing stringified (quote enclosed) nested objects with Jackson but for C# and Newtonsoft Json.Net. The question is how to deserialize a nested string representation of JSON using Json.Net. Example response from REST endpoint:

{
    "Id": "abcd1234",
    "Foo": "{\"field1\": "abc", \"field2\": \"def\"}"
}

C# Model:

public class Model {
    public Guid Id { get; set; }
    public Dictionary<string, string> Foo { get; set; }
}

Just calling JsonConvert.DeserializeObject<Model>(returnedJson) will error out because Foo in its returned form is stringified JSON, aka just a string. This is the case for other fields in our JSON response as well that have different Dictionary types associated in their models (e.g. Dictionary<string, int> and Dictionary<string, DateTime>).

What's the simplest way to handle this? Is a custom JsonConverter necessary or is there some built-in way to handle it?

2

2 Answers

3
votes

A JsonConverter is probably the simplest way to handle this implicit conversion. Here's one that works for your case.

public class MyConverter: JsonConverter
{
  public override bool CanConvert(Type objectType)
  {
    return objectType == typeof(string);
  }

  public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
  {
    return JsonConvert.DeserializeObject(reader.Value as string, objectType);
  }

  public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
  {
    throw new NotImplementedException();
  }
}

And then you decorate that property with the attribute like this:

public class Model
{
  public string Id { get; set; }
  [JsonConverter(typeof(MyConverter))]
  public Dictionary<string, string> Foo { get; set; }
}
2
votes

Just to follow up, I used a very similar solution to what @VijayeR recommended, but needed to tweak it a bit as it was still causing some problems for me. One issue is that when using the decorator, apparently CanConvert doesn't get called at all because Json.Net assumes you've assigned the correct converter to that property. This is what worked for me:

public class NestedJsonConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return true;
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var jToken = JToken.Load(reader);

        if (jToken.Type == JTokenType.String)
        {
            jToken = JToken.Parse((string) jToken);
        }

        return jToken.ToObject(objectType);
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }

    public override bool CanWrite => false;
}