0
votes

I have a JSON object that I get from my REST API server that looks like this:

"settings": {
  "assets.last_updated_at": "2016-08-24T23:40:26.442Z",
  "data.version": 34
}

Normally I'd deserialize the object to a Dictionary of string to object, but I'd like to provide helper methods to get strongly typed versions of the values. I'm using JSON.NET to deserialize the JSON object. Here's what I've got so far:

[JsonConverter(typeof(SettingsJsonConverter))]
public class Settings
{
    [JsonIgnore]
    public Dictionary<string, string> Entries { get; private set; }

    public Settings()
    {
        this.Entries = new Dictionary<string, string>();
    }
}

In order to wrap the dictionary within a class, it seems like I needed to create a custom JsonConverter, which currently looks like this:

public class SettingsJsonConverter : JsonConverter
{
    #region implemented abstract members of JsonConverter

    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)
    {
        JObject settingsObj = JObject.Load(reader);
        Settings settings = new Settings();

        foreach(KeyValuePair<string, JToken> entry in settingsObj)
        {
            settings.Entries.Add(entry.Key, entry.Value.ToString());
        }

        return settings;
    }

    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(Settings);
    }

    #endregion
}

Now obviously I could create methods in my Settings class like, GetDate that takes the value for a given key and creates a new DateTime object with the ISO string value. However, JSON.NET already provides facilities to do what I want to do, so I'd rather use its built-in deserialization for any values I iterate over, instead of doing it myself.

It seems as though the place to do this would be inside the foreach loop in SettingsJsonConverter#ReadJson, but I'm not quite sure how to get the Type (not a JTokenType, a standard C# Type) of a given JToken so I can pass it into JToken#ToObject(Type). Or, how can I iterate over a JsonReader to populate my internal Entries dictionary with already deserialized values, such that I just need to do simple casts in my helper methods in Settings? Here's how I'd like my Settings class to look:

[JsonConverter(typeof(SettingsJsonConverter))]
public class Settings
{
    [JsonIgnore]
    public Dictionary<string, object> Entries { get; private set; }

    public Settings()
    {
        this.Entries = new Dictionary<string, object>();
    }

    public DateTime GetDate(string key)
    {
        return (DateTime)this.Entries[key];
    }
}

Am I even doing this correctly? It almost feels like there's some simple way I'm overlooking.

2
Can you please put your json which you want to deserialize?Lalit Rajput
Hi, Lalit. Please see the first code block I posted, beginning with "settings": { ... }.Monkey34
this is not valid json. I think you have missed {} .I mean corrected json should be { "settings": { ... } }. Ok see my answer. It would be helpful to you.Lalit Rajput

2 Answers

0
votes

You can directly deserialize into a Dictionary<string, JToken> and use type casts as you need them so you don't need a Settings class or a custom converter. It doesn't look as nice as your solution, but the code is simpler:

var settings = JsonConvert.DeserializeObject<Dictionary<string, JToken>>(json);
var date = (DateTime) settings["key"];

If you want to keep your Settings class, I'd suggest that you use the above line to deserialize the dictionary and create a new constructor in Settings with a dictionary parameter, so you end up with two constructors, one that creates a new dictionary, and one that uses a given dictionary to create the new one. (Don't re-use the parameter dictionary itself, you never know what the caller will do to the dictionary afterwards.)

public Settings(Dictionary<string, JToken> dict)
{
    Entries = new Dictionary<string, JToken>(dict);
}

By the way, you can remove the JsonIgnore attribute because you have a custom converter class.

-1
votes

First of all we have to make a model for your corresponding json.

{
  "settings": {
          "assets.last_updated_at": "2016-08-24T23:40:26.442Z",
        "data.version": 34
   }
}

CSharp Model:

public class Settings
    {
        [JsonProperty("assets.last_updated_at")]
        public string assets_last_updated_at { get; set; }

        [JsonProperty("data.version")]
        public int data_version { get; set; }

       // Add other property here...
    }

    public class RootObject
    {
        public Settings settings { get; set; }
    }

Deserialize Json string to Model :

RootObject rootObject = JsonConvert.DeserializeObject<RootObject>("Put your Json String");

Hope this help.