Search code examples
c#json.net-6.0json-deserialization

Is there a better way of decoding a json in C# where the name of the key varies?


I have a response from an external api that looks like this, if i send in properties like this:

{ 
 "color": "blue"
 "type": "dog"
}

and then if i enter an invalid value of any of these i get a short error message back and a longer description for the property i sent in that was wrong. So lets say i send in

{ 
 "color": "blue"
 "type": "banana"
}

I would get

{
  "problem": "invalid pet",
  "type": "banana is not a valid type of pet ",
  "messageProperties": [
   "color",
   "type" ]
}

Then if i send in

{
  "color": "banana",
  "type: "dog"
}

I would get

{
  "problem": "wrong pet color",
  "color": "banana is not a valid color for a pet",
   "messageProperties": [
   "color",
   "type" ]
}

Is there an easy way of handling this? The best solution i found so far feels overly complex. Is there a better way? I'm using .NET 6

    public class MyErrorClass
    {
        public MyErrorClass(string json)
        {
            
            dynamic data = JsonConvert.DeserializeObject<dynamic>(json);
            foreach (KeyValuePair<string, JToken> kw in ((JObject)((JContainer)data)))
            {
                switch (kw.Key)
                {
                    case "context":
                        context = (string) kw.Value;
                        break;
                    case "messageProperties":
                    {
                        List<JToken> children = kw.Value.Children().ToList();
                        messageVariables = children.Values<string>().ToList();
                        break;
                    }
                    default:
                        error = (string) kw.Value;
                        break;
                }
            }
        }
        public string context { get; set; }
        public string error { get; set; }
        public List<string> messageVariables { get; set; }
    }

Solution

  • One approach is to use JsonExtensionData. For example:

    class Resp
    {
        public string Problem { get; set; }
        public List<string> MessageProperties { get; set; }
        [JsonIgnore]
        public Dictionary<string, string> Extras { get; set; }
    
        [JsonExtensionData]
        private IDictionary<string, JToken> _additionalData;
        [OnDeserialized]
        private void OnDeserialized(StreamingContext context)
        {
            Extras = _additionalData.ToDictionary(d => d.Key, d => d.Value.ToString());
        }
    }
    

    Or based on your example:

    class MyErrorClass
    {
        public string Problem { get; set; }
        public List<string> MessageProperties { get; set; }
        [JsonIgnore]
        public string Error { get; set; }
    
        [JsonExtensionData]
        private IDictionary<string, JToken> _additionalData;
        [OnDeserialized]
        private void OnDeserialized(StreamingContext context) => Error = _additionalData?.FirstOrDefault().Value?.ToString();
    }