Search code examples
c#jsonjson.netdeserializationjson-deserialization

C# - Unexpected character encountered while parsing value: {. Path '[0].Statistics


I am trying to deserialize a JSON object according to my model using the code below:

LoadData<MyModel>(Data.Stats, null);

public void LoadData<TModel>(string data, JsonSerializerSettings jsonSettings) where TModel : class
{
    var mockData = JsonConvert.DeserializeObject<Collection<TModel>>(data, jsonSettings); // ERROR HERE
    Context.SaveChanges();
}

However I am getting an error that reads

Newtonsoft.Json.JsonReaderException: 'Unexpected character encountered while parsing value: {. Path '[0].Statistics', line 7, position 19.'

My JSON object is:

[
  {
    "Id": 3033,
    "Grade": 3,
    "Statistics": { //ERROR OCCURS ON THIS PROPERTY
      "Avatar.Add": 1,
      "TotalPlays": 36,
      "Game.TotalPlays.Spell_Mem_Words": 27,
      "Book.TotalReads.Count": 23,
      "Game.TotalPlays.Count": 39,
      "Character.TotalPlays.L": 23,
      "Character.TotalPlays.E": 3,
      "TotalPlays.Pick_Vocab": 16,
      "Character.TotalPlays.R": 22
    }
  }
]

The Object Model is:

public class MyModel
{
    public int Id { get; set; }
    public int Grade { get; set; }
    public string Statistics { get; set; } 
}

Things I Have Tried

(1) Using json lint I have ensured that the json string is valid.

(2) In javascript serializing the object with back ticks surrounding it works. Backticks don't work in C# JS Fiddle

(3) Tried making the Statistics property in object model to use class called stats instead of string like

public class Stats 
{
    public string Label { get; set;}
    public int Value { get; set; }
}

(4) Tried nearly all the answers on this SO post

Unfortunately I still have not solved this issue. Any ideas?


Solution

  • I was able to reproduce the problem with this MCVE:

    using Newtonsoft.Json;
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.IO;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace DeserializeJson
    {
        /**
         * REFERENCE:
         * https://stackoverflow.com/questions/53562566/
         *
         * ORIGINAL ERROR:
         * "Unexpected character encountered while parsing value: {. Path '[0].Statistics', line 5, position 19."
         */
         public class Stats
         {
             public string Label { get; set; }
             public int Value { get; set; }
         }
    
         public class MyModel
         {
             public int Id { get; set; }
             public int Grade { get; set; }
             public string Statistics { get; set; }
         }
    
        class Program
        {
            static Collection<MyModel> LoadData(string data)
            {
                var retval = JsonConvert.DeserializeObject<Collection<MyModel>>(data);
                return retval;
            }
    
            static void Main(string[] args)
            {
                try
                {
                    string s = File.ReadAllText(@"test-data.json");
                    JsonConvert.DefaultSettings = () => new JsonSerializerSettings
                    {
                        Formatting = Newtonsoft.Json.Formatting.Indented
                    };
                    Collection <MyModel> mockData = Program.LoadData(s);
                    System.Console.WriteLine("#/items= " + mockData.Count);
                    foreach (MyModel item in mockData)
                    {
                        System.Console.WriteLine("  id= {0}, Grade={1}, Statistics={2}", item.Id, item.Grade, item.Statistics.ToString());
                    }
                }
                catch (Exception ex)
                {
                    System.Console.WriteLine("ERROR:", ex);
                }
            }
        }
    }
    

    I was able to fix it by:

    1. Elaborating your definition of class Stats, then
    2. Using Stats in the definition of class MyModel:

      public class Stats
      {
          public int AvatarAdd { get; set; }
          public int TotalPlays { get; set; }
          public int GameTotalPlaysSpellMemWords { get; set; }
          public int BookTotalReadsCount { get; set; }
          public int GameTotalPlaysCount { get; set; }
          public int CharacterTotalPlaysL { get; set; }
          public int CharacterTotalPlaysE { get; set; }
          public int TotalPlaysPick_Vocab { get; set; }
          public int CharacterTotalPlaysR { get; set; }
      }
      
      public class MyModel
      {
          public int Id { get; set; }
          public int Grade { get; set; }
          public Stats Statistics { get; set; }
      }
      

    You have several choices (including use the above example verbatim). My suggestion would be to break "Statistics" down into smaller model classes.