I am using NewtonSoft's JsonConvert.DeserializeObject<AppraiserCalendarDto>(content)
method and am trying to de-serialize the following content to find out if a resource is working on particular 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 is as follows:
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 the List<Link> Links
gets populated and the Records
dictionary is null.
I tried using Dictionary<string, Record>
instead of Dictionary<DateTime, Record>
with the same result.
Any feedback is greatly appreciated.
There are two issues here contributing to the problem. First, the time entries which you intend to go into the dictionary are at the same level in the JSON as the links
object. The deserializer does not see them because it is expecting them to be inside an object called records
in the JSON, corresponding to the name of the dictionary property in your AppraiserCalendarDto
class. The second issue is that each time entry record is inside an object called regular
in the JSON, but there is no corresponding class for that in your model.
One possible solution is to change the JSON to match your model, assuming you have control over the JSON format. However, in most questions I come across of this type, that is not an option because the JSON is usually a third-party API outside the asker's control. If that is the case, then the other option is to implement a custom JsonConverter
to bridge the gap. Here is 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 AppraiserCalendarDto
class with a [JsonConverter]
attribute like this:
[JsonConverter(typeof(AppraiserCalendarDtoConverter))]
public class AppraiserCalendarDto
{
...
}
Or, alternatively, you can pass an instance to JsonConvert.DeserializeObject<T>
like this:
var dto = JsonConvert.DeserializeObject<AppraiserCalendarDto>(content,
new AppraiserCalendarDtoConverter());
Demo fiddle: https://dotnetfiddle.net/yyErtO