0

Given some json that looks like

{
  "id":"123_678",
  "fs_123_678":
   {
     "title":"Apple Parts",
     "data": 134
   }
}

I'd like to deserialize it into the following classes

public class Result
{
   public string Id {get; set;}
   public ResultInfo Info {get; set;}
}

public class ResultInfo
{
   public string Title {get; set;}
   public int Data {get; set;}
}

... but that second property (fs_123_678) is not a fixed name. I've looked at other similar posts on SO here, and the common solution is to use a IDictionary<string, MyPoco> however, that only works when the variable data is not at the root level. The name of the property is 100% predictable, and I could describe in code what it will be for a given JSON response based off of values used in the source HTTP request. The trick is, how do I let the JSON deseralizer in on the business rule around what it will be called for this given deserialization? I basically need something that would act like [JsonProperty(PropertyName = *insert logic here*)] (which of course isn't possible).

What's a reasonable way to approach this, all while retaining the "for free" strong-typed deserialization of the rest of the object?

6
  • I'd write a custom deserializer (JSON.NET has a great article about it on their site). Commented Aug 23, 2017 at 0:27
  • @SamAxe awesome, I was looking in the "Serializing and Deserializing JSON" section (newtonsoft.com/json/help/html/SerializingJSON.htm) and I didn't see anything that would help me out - but maybe I missed it? Got a handy dandy link by chance? Commented Aug 23, 2017 at 0:55
  • You could use [JsonTypedExtensionData] and TypedExtensionDataConverter<ResultInfo> from How to deserialize a child object with dynamic (numeric) key names?. Or you could write a custom JsonConverter for Result as shown in, say, this answer or this one. Commented Aug 23, 2017 at 1:17
  • newtonsoft.com/json/help/html/CustomJsonConverter.htm Commented Aug 23, 2017 at 4:31
  • Can someone link to the "similar" posts? I've also searched, but I can't find them, and it sounds like I can use dictionaries but its not clear how to me. Commented Jul 20, 2022 at 12:58

1 Answer 1

1

Based on the links that dbc provided in comments, I found that this solution appears to be functional, but open to other suggestions. I'm bascially taking the current reader stream, loading it as a JObject then replacing the original JProperty with another that has the name my model is expecting.

public class MyCustomResultConverter : JsonConverter
{
    public override bool CanWrite => false;
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var obj = JObject.Load(reader);
        var formData = obj.SelectToken("fs_" + obj.SelectToken("id").Value<string>());
        formData.Parent.Replace(new JProperty("info", formData));

        existingValue = existingValue ?? new FormActionResult();
        serializer.Populate(obj.CreateReader(), existingValue);
        return existingValue;
    }

    public override bool CanConvert(Type objectType)
    {
        return typeof(Result).GetTypeInfo().IsAssignableFrom(objectType);
    }
}

[JsonConverter(typeof(MyCustomResultConverter))]
public class Result
{
   public string Id {get; set;}
   public ResultInfo Info {get; set;}
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.