2017-05-19 4 views
3

J'utilise la méthode JsonConvert.DeserializeObject<AppraiserCalendarDto>(content) de NewtonSoft et essaie de désérialiser le contenu suivant pour savoir si une ressource travaille à ce jour particulier:JSON désérialiser au dictionnaire ne fonctionne pas correctement

{ 
    "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" 
    } 
    ] 
} 

Ma classe de modèle à population est comme suit:

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; } 
    } 
} 

Malheureusement seulement le List<Link> Links peuplé et le obtient le dictionnaire Records est nul. J'ai essayé d'utiliser Dictionary<string, Record> au lieu de Dictionary<DateTime, Record> avec le même résultat.

Tout commentaire est grandement apprécié.

Répondre

2

Deux problèmes sont à l'origine du problème. Tout d'abord, les entrées de temps que vous avez l'intention d'entrer dans le dictionnaire sont au même niveau dans le JSON que l'objet links. Le désérialiseur ne les voit pas car il s'attend à ce qu'ils soient à l'intérieur d'un objet appelé records dans le JSON, correspondant au nom de la propriété de dictionnaire dans votre classe AppraiserCalendarDto. Le deuxième problème est que chaque enregistrement d'entrée de temps est dans un objet appelé regular dans le JSON, mais il n'y a pas de classe correspondante pour cela dans votre modèle.

Une solution possible consiste à modifier le JSON pour qu'il corresponde à votre modèle, en supposant que vous ayez le contrôle sur le format JSON. Cependant, dans la plupart des questions que je rencontre de ce type, ce n'est pas une option parce que le JSON est généralement une API tierce en dehors du contrôle du demandeur. Si tel est le cas, l'autre option consiste à implémenter un JsonConverter personnalisé pour combler le vide. Voici un convertisseur qui devrait fonctionner pour vous:

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(); 
    } 
} 

Pour utiliser le convertisseur vous pouvez marquer votre AppraiserCalendarDto classe avec un attribut [JsonConverter] comme ceci:

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

Ou, alternativement, vous pouvez passer un par exemple à JsonConvert.DeserializeObject<T> comme ceci:

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

violon de démonstration: https://dotnetfiddle.net/yyErtO

+0

Merci, cela a parfaitement fonctionné. – zmeikov

+0

Pas de problème; heureux d'avoir pu aider. –

0

J'ai vérifié votre JSON et c'est bon; Je pense que le problème est que JsonConvert.DeserializeObject n'a pas la logique de placer ces entités répétitives dans un dictionnaire intrinsèquement. Alors, voici ce que j'ai regardé. D'abord, j'ai pris votre JSON et j'ai utilisé VS edit -> paste special -> coller en tant que classes json. J'ai eu un vrai bordel, voir le generated file ici. En supposant que Newtonsoft et VS suivent une logique d'interprétation JSON similaire, il semblerait que ces instances d'enregistrement successives soient interprétées chacune comme une entité unique plutôt que comme une collection ou un tableau. Je pense que vous devrez utiliser une logique personnalisée pour analyser le json dans vos classes. Désérialisez-le simplement en un objet dynamique et travaillez votre chemin à travers. Bonne chance!