John Miller
John Miller

Reputation: 161

Using JSON.NET and C# reading file and deserialize the JSON fails

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?

Upvotes: 2

Views: 1704

Answers (4)

trashr0x
trashr0x

Reputation: 6565

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.

Upvotes: 3

Thomas Levesque
Thomas Levesque

Reputation: 292405

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

Upvotes: 4

Orel Eraki
Orel Eraki

Reputation: 12196

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

Upvotes: 1

Kenneth
Kenneth

Reputation: 28737

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

Upvotes: 1

Related Questions