0

I'm dealing with a 3rd Party API that returns data like this:

{
  "dynamicFields": {
    "prop1": "val1",
    "prop2": "val2",
    "prop3": "val3"
  },
  // otherFields ...
}

Since these "dynamic fields" are not strongly typed. I want to represent my POCO as:

class ApiResponse {
  public DynamicFields DynamicFields { get; get; }
}

class DynamicFields {
  public Dictionary<string, string> Values { get; set; }
}

The rub is, I want to be able to prefix the keys in the dictionary, such that they have the parent property name like so:

{
  "DynamicFields": {
    "dynamicFields.prop1": "val1",
    "dynamicFields.prop2": "val2",
    "dynamicFields.prop3": "val2",
  }
}

However, it doesn't look like System.Text.Json.Serialization.JsonConverter<T> gives me access to the parent property name. Is there another way to accomplish this such that I can get the desired output? I'm really trying to not use Newtonsoft/Json.NET as I believe System.Text.Json is "the future".

class DynamicFieldConverter : JsonConverter<DynamicField>
{
    public override DynamicField Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        // How do I get the name of the parent property here?
        ...
    }

    public override void Write(Utf8JsonWriter writer, DynamicField value, JsonSerializerOptions options)
    {
        ...
    }
}
dbc
  • 104,963
  • 20
  • 228
  • 340
brendonparker
  • 838
  • 8
  • 19

1 Answers1

0

Here my solution for your case:

  1. DynamicFieldConverter class
    public class DynamicFieldConverter : JsonConverter<DynamicFields>
    {
        private const string MainPropName = "dynamicFields";

        public override DynamicFields Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            var dictionary = new Dictionary<string, string>();

            var startDepth = reader.CurrentDepth;
            while (reader.Read())
            {
                if (reader.TokenType == JsonTokenType.EndObject && reader.CurrentDepth == startDepth)
                {
                    return new DynamicFields
                    {
                        Values = dictionary
                    };
                }

                if (reader.TokenType == JsonTokenType.PropertyName)
                {
                    var propertyName = reader.GetString();
                    if(propertyName == MainPropName)
                        continue;

                    var value = JsonSerializer.Deserialize<string>(ref reader, options);
                    dictionary.Add($"{MainPropName}.{propertyName}", value);
                }
            }

            throw new JsonException();
        }

        public override void Write(Utf8JsonWriter writer, DynamicFields value, JsonSerializerOptions options)
        {
        }
    }
  1. JsonConverterAttribute for class
    [JsonConverter(typeof(DynamicFieldConverter))]
    public class DynamicFields
    {
        public Dictionary<string, string> Values { get; set; }
    }
  1. Finally, console to test it
        static void Main(string[] args)
        {
            var json = "{\r\n  \"dynamicFields\": {\r\n    \"prop1\": \"val1\",\r\n    \"prop2\": \"val2\",\r\n    \"prop3\": \"val3\"\r\n  }\r\n}";

            var obj = JsonSerializer.Deserialize<DynamicFields>(json);
        }
DarkSideMoon
  • 835
  • 1
  • 11
  • 17
  • Why on Earth it is so complex?? Where isn't a simpler way? I just want ot catch what I am trying to parse (name / value) and output in Exception text... – Alexander Nov 08 '21 at 19:17