De-Serialize json for a dictionary not working as expected

I am using the NewtonSoft method JsonConvert.DeserializeObject<AppraiserCalendarDto>(content)

and am trying to de-serialize the following content to see if a resource is running on a specific date:

{
  "2017-05-18": {
    "regular": {
      "recordType": "working",
      "workTimeStart": "08:00",
      "workTimeEnd": "22:00"
    }
  },
  "2017-05-19": {
    "regular": {
      "recordType": "working",
      "workTimeStart": "08:00",
      "workTimeEnd": "22:00"
    }
  },
  "2017-05-22": {
    "regular": {
      "recordType": "working",
      "workTimeStart": "08:00",
      "workTimeEnd": "22:00"
    }
  },
  "2017-05-23": {
    "regular": {
      "recordType": "working",
      "workTimeStart": "08:00",
      "workTimeEnd": "22:00"
    }
  },
  "2017-05-24": {
    "regular": {
      "recordType": "working",
      "workTimeStart": "08:00",
      "workTimeEnd": "22:00"
    }
  },
  "2017-05-25": {
    "regular": {
      "recordType": "working",
      "workTimeStart": "08:00",
      "workTimeEnd": "22:00"
    }
  },
  "2017-05-26": {
    "regular": {
      "recordType": "working",
      "workTimeStart": "08:00",
      "workTimeEnd": "22:00"
    }
  },
  "links": [
    {
      "rel": "canonical",
      "href": "https://api.somedomain.com/rest/core/v1/resources/workSchedules/calendarView?dateFrom=2017-05-18&dateTo=2017-05-28"
    },
    {
      "rel": "describedby",
      "href": "https://api.somedomain.com/rest/core/v1/metadata-catalog/resources"
    }
  ]
}

      

My model class to be populated looks like this:

public class AppraiserCalendarDto
{
    public Dictionary<DateTime, Record> Records { get; set; }

    public class Record
    {
        [JsonProperty("recordType")]
        public string RecordType { get; set; }

        [JsonProperty("workTimeStart")]
        public TimeSpan WorkTimeStart { get; set; }

        [JsonProperty("workTimeEnd")]
        public TimeSpan WorkTimeEnd { get; set; }
    }

    public List<Link> Links { get; set; }

    public class Link
    {
        [JsonProperty("rel")]
        public string Rel { get; set; }

        [JsonProperty("href")]
        public string Href { get; set; }
    }
}

      

Unfortunately only populated List<Link> Links

and the dictionary Records

is null.

I tried using Dictionary<string, Record>

instead Dictionary<DateTime, Record>

with the same result.

Any feedback is greatly appreciated.

+3


source to share


2 answers


There are two problems with this problem. First, the temporary entries that you are going to enter into the dictionary are flush in JSON as an object links

. The Deserializer doesn't see them because it expects them to be inside a records

JSON named object that matches the name of the dictionary property in your class AppraiserCalendarDto

. The second problem is that each time record is inside an object named regular

in JSON, but no corresponding class exists for your model.

One possible solution is to change the JSON to fit your model, assuming you are in control of the JSON format. However, in most of the questions I come across with this type, this is not an option, because JSON is usually a third party API outside of the control item. If so, then another option is to implement a custom JsonConverter

one to close the gap. Here's a converter that should work for you:

class AppraiserCalendarDtoConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return (objectType == typeof(AppraiserCalendarDto));
    }

    public override object ReadJson(JsonReader reader, Type objectType, 
                                    object existingValue, JsonSerializer serializer)
    {
        JObject jo = JObject.Load(reader);
        var dto = new AppraiserCalendarDto();
        dto.Links = jo["links"].ToObject<List<AppraiserCalendarDto.Link>>();
        var dict = new Dictionary<DateTime, AppraiserCalendarDto.Record>();
        dto.Records = dict;
        foreach (JProperty prop in jo.Properties().Where(p => p.Name != "links"))
        {
            var date = DateTime.Parse(prop.Name);
            var record = prop.Value["regular"].ToObject<AppraiserCalendarDto.Record>();
            dict.Add(date, record);
        }
        return dto;
    }

    public override bool CanWrite
    {
        get { return false; }
    }

    public override void WriteJson(JsonWriter writer, 
                                   object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

      

To use the converter, you can either mark your class with an AppraiserCalendarDto

attribute [JsonConverter]

like this:



[JsonConverter(typeof(AppraiserCalendarDtoConverter))]
public class AppraiserCalendarDto
{
    ...
}

      

Or, alternatively, you can pass an instance in JsonConvert.DeserializeObject<T>

like this:

var dto = JsonConvert.DeserializeObject<AppraiserCalendarDto>(content,
          new AppraiserCalendarDtoConverter());

      

Demo script: https://dotnetfiddle.net/yyErtO

+2


source


I checked your JSON and it's good; I think the problem is that JsonConvert.DeserializeObject has no logic to put these duplicate objects into a dictionary per se. So here's what I looked at. First, I took your JSON and used VS edit -> paste special -> paste as json classes. I have a real mess, see the generated file here. Assuming Newtonsoft and VS follow similar JSON interpretation logic, it would seem that these sequential record instances are interpreted as a unique entity, not a collection or array. I think you will have to use some custom logic to parse json in your classes. Just deserialize it to a dynamic object and work your way through it. Good luck!



0


source







All Articles