0

I want to deserialize a complex and let's say not well constructed json. That code that I wrote doesn't deserialize the object, the MovieInfo property is null. You can find the example json in the code. I want to avoid using JObject.Parse and dynamic objects. What am I missing here?

using System.Collections.Generic;
using Newtonsoft.Json;

namespace ComplexJsonExample
{
    class Program
    {
        static void Main(string[] args)
        {
            string jsonInText = @"
            {
                ""movies"" : [
                    { 
                        ""Harry Potter"" : [
                            { ""rating"": ""great""}, 
                            { ""rating"": ""horrible""}
                        ]
                    },
                    { 
                        ""Guardians of the galaxy"" : [
                            { ""rating"": ""cool""}, 
                            { ""rating"": ""awesome""}
                        ]
                    }
                ]
            }
            ";

            var movieList = JsonConvert.DeserializeObject<MovieList>(jsonInText);
        }
    }

    public class MovieList
    {
        [JsonProperty("movies")]
        public IList<Movie> Movies { get; set; }
    }

    public class Movie
    {
        IDictionary<string, IList<MovieRating>> MovieInfo { get; set; }
    }

    public class MovieRating
    {
        [JsonProperty("rating")]
        public string Rating { get; set; }
    }
}
Balázs Szántó
  • 1,440
  • 3
  • 15
  • 29
  • what are you missing? Well formed json! – Jamiec Sep 18 '14 at 10:18
  • The problem is that not I'm the one who created the json, this is given as is. – Balázs Szántó Sep 18 '14 at 10:20
  • You might want to check this question/answer: http://stackoverflow.com/questions/9452901/cannot-deserialize-json-array-into-type-json-net/9453191#9453191 – Jamiec Sep 18 '14 at 10:21
  • The problem is; your json contains double-double-quotes. What if you used a simple hack like this: `var movieList = JsonConvert.DeserializeObject(jsonInText.Replace("\"\"", "\""));` – Latheesan Sep 18 '14 at 10:27

2 Answers2

1

I consider this a bit of a hack, but it works, and deserializes your json string into the format you required:

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

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {            

        var movie = new Movie(){
            MovieInfo = new Dictionary<string,IList<MovieRating>>()
        };

        while (reader.Read() && reader.Value != null)
        {                
            var name = (string)reader.Value;

            reader.Read();

            var ratings = ((JArray)serializer.Deserialize(reader)).Values<string>("rating");

            movie.MovieInfo.Add(name, ratings.Select(r => new MovieRating(){ Rating = r}).ToList());
        }
        return movie;
    }

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

I did have to make two changes to your original objects, first I made the accessor for MovieInfo public so I could access it, and second to add the JsonConverterAttribute:

[JsonConverter(typeof(MovieConverter))]
public class Movie
{
    public IDictionary<string, IList<MovieRating>> MovieInfo { get; set; }
}
Jamiec
  • 133,658
  • 13
  • 134
  • 193
1

It's a bit ugly, but you can do it like this:

class MovieList
{
    [JsonProperty("movies")]
    public Movie[] Movies { get; set; }
}

class Movie : Dictionary<string, MovieRating[]>
{
}

class MovieRating
{
    [JsonProperty("rating")]
    public string Rating { get; set; }
}

It's weird that the movie is a dictionary with only one key (its title), but it matches the JSON structure. You can always map it to something more sensible after deserialization.

Thomas Levesque
  • 286,951
  • 70
  • 623
  • 758