2

I have a JSON file named 'movies.json' which contains an object and an array of 3 movies. The JSON in movies.json looks like this:

{
  "theMovies": [
    {
      "name": "Starship Troopers",
      "year": 1997
    },
    {
      "name": "Ace Ventura: When Nature Calls",
      "year": 1995
    },
    {
      "name": "Big",
      "year": 1988
    }
  ]
}

I also have a class named Movie

public class Movie
{
    public string Name { get; set; }
    public int Year { get; set; }
}

I am trying to read the file into a string and deserialize the JSON to a type of Movie like this:

 Movie movie1 = JsonConvert.DeserializeObject<Movie>(File.ReadAllText(@"c:\Temp\movies.json"));

and like this:

using (StreamReader file = File.OpenText(@"c:\Temp\movies.json"))
        {
            JsonSerializer serializer = new JsonSerializer();
            Movie movie2 = (Movie)serializer.Deserialize(file, typeof(Movie));
            Console.WriteLine(movie2.Name);
            Console.WriteLine(movie2.Year);
        }

Neither one works. Both movie1 and movie2 show no real data the Watch window:

movie1.Name = null
movie1.Year = 0
movie2.Name = null
movie2.Year = 0

Apparently having an object with an array inside is not working. Any suggestions?

2
  • You defined a class for the individual movies, but you didn't define one for the enclosing object that holds those movies... That object is not a movie. Commented Jan 28, 2016 at 0:08
  • Your json file represents an object containing a property with an array of movies (Movie[]) so that's what you need to deserialize to Commented Jan 28, 2016 at 0:08

4 Answers 4

4

The full JSON document is not a Movie, it's an object with a property theMovies that contains an array of Movies. So you can't deserialize the full JSON document into a Movie, since its structure doesn't match the target type.

You can either:

  • create a class that represents the whole document and deserialize this class:

    class MyDocument
    {
        [JsonProperty("theMovies")]
        public Movie[] Movies { get; set; }
    }
    

    You can then access the first item in document.Movies

  • or get the node that contains the first movie, and deserialize it:

    var doc = JObject.Parse(File.ReadAllText(@"c:\Temp\movies.json"));
    var theMovies = doc["theMovies"] as JArray;
    var firstMovie = theMovies[0].ToObject<Movie>();
    
Sign up to request clarification or add additional context in comments.

Comments

3

In JSON, anything enclosed in [ ] denotes a collection and anything enclosed in { } denotes an object (see my answer here). So, you can see that you have an object containing a collection called theMovies, consisting of 3 objects (in this case, movies) with 2 properties each. If you think of these in C# terms, you could have a class (which would act as the root object, let's call it MyJsonDocument) containing an IEnumerable<Movie> (which would act as theMovies collection) to hold each Movie object in.

public class MyJsonDocument
{
    //  JsonProperty indicates how each variable appears in the JSON, _
    //  so the deserializer knows that "theMovies" should be mapped to "Movies". _
    //  Alternatively, your C# vars should have the same name as the JSON vars.
    [JsonProperty("theMovies")]
    public List<Movie> Movies { get; set; }
}

public class Movie
{
    [JsonProperty("name")]
    public string Name { get; set; }
    [JsonProperty("year")]
    public int Year { get; set; }
}

Now that you have your structure set up:

var myJsonDocument = JsonConvert.DeserializeObject<MyJsonDocument>(File.ReadAllText(@"C:\Users\trashr0x\Desktop\movies.json"));
foreach(Movie movie in myJsonDocument.Movies)
{
    Console.WriteLine(string.Format("{0} ({1})", movie.Name, movie.Year));
    // or with C# 6.0:
    Console.WriteLine($"{movie.Name} ({movie.Year})");
}

Output:

Starship Troopers (1997)

Ace Ventura: When Nature Calls (1995)

Big (1988)

As an aside, you might also want to consider what happens when some of the JSON properties are empty (for example, no year listed for a particular movie). You would have to convert Year to be an int? (nullable integer) instead of an int. If you are 100% confident that all properties in the JSON will be always populated then you can ignore this.

2 Comments

Thank you to everyone who helped! Each answer helped me to understand where I had gone wrong. I marked #trashr0x as the correct answer because it seemed the most complete.
Hey, you're welcome. You should upvote all of the answers you found useful as well.
1

Your class structure should match your json file.

Try the following:

class MovieList
{
    public List<Movie> TheMovies {get; set;}
}
public class Movie
{
    public string Name { get; set; }
    public int Year { get; set; }
}

using (StreamReader file = File.OpenText(@"c:\Temp\movies.json"))
{
    JsonSerializer serializer = new JsonSerializer();
    MovieList movies = (MovieList)serializer.Deserialize(file, typeof(MovieList));
    foreach(var movie in movies.TheMovies)
    {
        Console.WriteLine(movie.Name);
        Console.WriteLine(movie.Year);
    }
}

Comments

1

You're trying to deserialize List X object to Movie object, which they are not compatible.

var myLibrary = JsonConvert.DeserializeObject<MyLibrary>(File.ReadAllText(@"c:\Temp\movies.json"));

Models:

class MyLibrary
{
    public List<Movie> theMovies { get; set; }
}

public class Movie
{
    public string name { get; set; } // Changed to lower case, as the json representation.
    public int year { get; set; }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.