Reputation: 73
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.
Upvotes: 4
Views: 1075
Reputation: 1190
I checked your JSON and it's good; I think the issue is that JsonConvert.DeserializeObject doesn't have the logic to put those repeating entities into a dictionary intrinsicly. So here's what I've looked at. First, I took your JSON and used VS edit -> paste special -> paste as json classes. I got a real mess, see the generated file here. Assuming Newtonsoft and VS follow similar JSON interpretation logic, It would seem that those successive record instances are being interpretated each as a unique entity rather than a collection or an array. I think you're going to have to use some custom logic to parse the json into your classes. Just deserialize it to a dynamic object and work your way through it. Good luck!
Upvotes: 0
Reputation: 129657
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
Upvotes: 2