Question

I am using JSON.NET and have to deserialize this structure.

"NameValue": [
    {
      "Name": "CONO",
      "Value": "001"
    },
    {
      "Name": "DIVI",
      "Value": "   "
    },
    {
      "Name": "LNCD",
      "Value": "DE"
    },
    {
      "Name": "CUNO",
      "Value": "#AT-VORL  "
    },
]

It is part of a larger object and I would like to deserialize to MyType. I could have a property NameValue which is a list of objects typed MyNameValue which has two properties Name and Value. But this is only a weird representation of a dictionary (names will never overlap) so I would like to have a .NET dictionary which will be much more handy.

How can I achieve this using attributes on my classes?

What kind of works is this:

    private class JsonResponseRecord
    {
        public string RowIndex { get; set; }

        [JsonProperty(PropertyName = "NameValue")]
        public List<KeyValuePair<string, string>> Values { get; set; }
    }

But it ends up with a List of KeyValuePairs where all the keys are null while the value is filled correctly. I guess he would require the JSON to have "Key" instead of "Name".


To make clear: I would like to have a Dictionary<string, string> as type of Values property like:

    private class JsonResponseRecord
    {
        public string RowIndex { get; set; }

        [JsonProperty(PropertyName = "NameValue")]
        public Dictionary<string, string> Values { get; set; }
    }
Was it helpful?

Solution 3

I was able to do it with a custom converter. If this would be possible with JSON.NET standard I would appreciate the input nevertheless.

Here comes my receiving object:

internal class ResponseRecord
{
    public string RowIndex { get; set; }

    [JsonProperty(PropertyName = "NameValue"), JsonConverter(typeof(JsonNameValueListToDictionaryConverter))]
    public Dictionary<string, string> Values { get; set; }
}

This is the converter code:

/// <summary>
/// Converts the NameValue-array with object containing name and value to a Dictionary.
/// </summary>
internal class JsonNameValueListToDictionaryConverter : JsonConverter
{
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotSupportedException();
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        Dictionary<string, string> dictionary = existingValue as Dictionary<string, string> ?? new Dictionary<string, string>();

        if (reader.TokenType == JsonToken.StartArray)
        {
            int startDepth = reader.Depth;
            while (reader.Read())
            {
                if ((reader.Depth == startDepth) && (reader.TokenType == JsonToken.EndArray)) break;

                if (reader.TokenType == JsonToken.StartObject)
                {
                    KeyValuePair<string, string> kvp = GetKeyValueFromJsonObject(reader, "Name", "Value");
                    dictionary[kvp.Key] = kvp.Value; // always override existing keys
                }
                else
                {
                    throw new NotSupportedException(String.Format("Unexpected JSON token '{0}' while reading special Dictionary", reader.TokenType));
                }
            }
        }

        return dictionary;
    }

    private KeyValuePair<string, string> GetKeyValueFromJsonObject(JsonReader reader, string propNameKey, string propNameValue)
    {
        string key = null;
        string value = null;
        int startDepth = reader.Depth;
        while (reader.Read())
        {
            if ((reader.TokenType == JsonToken.EndObject) && (reader.Depth == startDepth)) break;

            if (reader.TokenType == JsonToken.PropertyName)
            {
                string propName = reader.Value as string;
                if (propName == null) continue;
                if (propName.Equals(propNameKey, StringComparison.InvariantCulture))
                {
                    key = reader.ReadAsString();
                }
                else if (propName.Equals(propNameValue, StringComparison.InvariantCulture))
                {
                    value = reader.ReadAsString();
                }
            }
        }
        return new KeyValuePair<string, string>(key, value);
    }

    public override bool CanConvert(Type objectType)
    {
        return (objectType.Equals(typeof(Dictionary<string, string>)));
    }

}

OTHER TIPS

First a little correction to the JSON string that you posted. It should look like this:

var json =  {
       "NameValue": [
        {
          "Name": "CONO",
          "Value": "001"
        },
        {
          "Name": "DIVI",
          "Value": "   "
        },
        {
          "Name": "LNCD",
          "Value": "DE"
        },
        {
          "Name": "CUNO",
          "Value": "#AT-VORL  "
        }
      ]
    }

You can acchieve what you want by using JSON.NET built in Linq to JSON. Here is the samlple code:

    var jObject = JObject.Parse(json);
    var jsonResponseRecordObj = new JsonResponseRecord
                {
                    Values =
                        jObject["NameValue"].ToDictionary(row => (string) row["Name"], row => (string) row["Value"])
                };

Use JSON.NET, Paste Special, "As JSON CLass", which gives you :-

public class Rootobject
{
public Namevalue[] NameValue { get; set; }
}

public class Namevalue
{
public string Name { get; set; }
public string Value { get; set; }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top