1

I'm having an issue deserializing a JSON string into a RootObject class with 1 string property and a list of custom objects.

When I debug the application and the code deserializes the json I get my 'ErrorCode' property, "test", is populated in the RootObject class but the 'meets' property is always null.

The code sits in a cross platform Xamarin forms application currently, but I've pulled the code and class definitions out and ran them in a simple console application that worked first time with no issues. I'm struggling to figure out what I'm doing wrong.

My simple JSON object is the following:

{"meets": [
    {
      "VenueName": "O2"
    },
    {
      "VenueName": "wembly"
    },
    {
      "VenueName": "NEC"
    }
  ],
  "ErrorCode": "test"}

My class definitions:

[JsonObject(Id = "Meets")]
public class Meets
{
    [JsonProperty(PropertyName = "VenueName")]
    public string VenueName { get; set; }
}

public class RootObject
{
    public List<Meets> Meets { get; set; }
    public string ErrorCode { get; set; }
}

The code to hit the api and get the json object (which is blanked out and a smaller simple object in its place):

using System;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Threading.Tasks;
using Xamarin.Forms;
using EliteNfcBet.Models;
using System.Net.Http;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;

namespace EliteNfcBet.ViewModels
{
    public class ItemsViewModel : BaseViewModel
    {
        public ObservableCollection<Meets> RaceMeets { get; set; }
        public Command LoadItemsCommand { get; set; }

        public ItemsViewModel   ()
        {
            Title = "Select Meeting";
            RaceMeets = new ObservableCollection<Meets>();
            LoadItemsCommand = new Command(async () => await ExecuteLoadItemsCommand());                       
        }

        async Task ExecuteLoadItemsCommand()
        {
            if (IsBusy)
                return;

            IsBusy = true;

            try
            {
                RaceMeets.Clear();
                var result = await GetMeetingsAsync();
                //RaceMeets = result;
                //foreach (var meet in meets.Meets)
                //{
                //    RaceMeets.Add(meet);
                //}
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex);
            }
            finally
            {
                IsBusy = false;
            }
        }

        public static async Task<RootObject> GetMeetingsAsync()
        {
            RootObject meet = new RootObject();
            //List<Meet> meets = new List<Meet>();
            HttpClient client = new HttpClient();
            client.MaxResponseContentBufferSize = 256000;

            var uri = new Uri(string.Format(Constants.RestUrl, string.Empty) + "/api/GetAvailablemeetings");

            try
            {
                var response = await client.GetAsync(uri);
                if (response.IsSuccessStatusCode)
                {
                    //var content = await response.Content.ReadAsStringAsync();
                    var content = "{\"meets\":[{\"VenueName\":\"O2\"},{\"VenueName\":\"wembly\"},{\"VenueName\":\"NEC\"}],\"ErrorCode\":\"test\"}";

                    if (!string.IsNullOrEmpty(content))
                    {

                        ITraceWriter traceWriter = new MemoryTraceWriter();

                        var settings = new JsonSerializerSettings
                        {
                            Error = (sender, args) =>
                            {
                                if (System.Diagnostics.Debugger.IsAttached)
                                {
                                    System.Diagnostics.Debugger.Break();
                                }
                            },
                            TraceWriter = traceWriter
                        };

                        //result = JsonConvert.DeserializeObject<T>(json, settings);
                        meet = JsonConvert.DeserializeObject<RootObject>(content, settings);
                        Console.WriteLine(traceWriter);
                    }

                    //if (meets.Count > 0)
                    //{
                    //    meet.MeetList = meets;
                    //}
                }
            }
            catch (Exception ex)
            {
                meet.ErrorCode = "INTERNAL_ERROR";
            }

            return meet;
        }
    }
}

EDIT:

I've made some minor changes suggested which are below.

My Json string is now this:

"{\"Meets\":[{\"VenueName\":\"O2\"},{\"VenueName\":\"wembly\"},{\"VenueName\":\"NEC\"}],\"ErrorCode\":\"test\"}"

My classes are below. One thing to note is they are defined within a 'models' namespace in a seperate code file that is doing the deserializing.

namespace EliteNfcBet.Models
{
public class Meets
{
    public string VenueName { get; set; }
}

public class RootObject
{
    public List<Meets> Meets { get; set; }
    public string ErrorCode { get; set; }
}

}

Again i have debugging output when deserializing which looks like it points to the fact that the Meets class member not being found?

{2018-05-28T23:12:22.987 Info Started deserializing EliteNfcBet.Models.RootObject. Path 'Meets', line 1, position 9.
2018-05-28T23:12:22.993 Info Started deserializing System.Collections.Generic.List`1[[NInterpret.InterpretedObject, NInterpret.Xamarin.Droid, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]. Path 'Meets', line 1, position 10.
2018-05-28T23:12:22.994 Info Started deserializing EliteNfcBet.Models.RootObject. Path 'Meets[0].VenueName', line 1, position 23.
2018-05-28T23:12:22.994 Verbose Could not find member 'VenueName' on EliteNfcBet.Models.RootObject. Path 'Meets[0].VenueName', line 1, position 23.
2018-05-28T23:12:22.994 Info Finished deserializing EliteNfcBet.Models.RootObject. Path 'Meets[0]', line 1, position 28.
2018-05-28T23:12:22.995 Info Started deserializing EliteNfcBet.Models.RootObject. Path 'Meets[1].VenueName', line 1, position 42.
2018-05-28T23:12:22.995 Verbose Could not find member 'VenueName' on EliteNfcBet.Models.RootObject. Path 'Meets[1].VenueName', line 1, position 42.
2018-05-28T23:12:22.996 Info Finished deserializing EliteNfcBet.Models.RootObject. Path 'Meets[1]', line 1, position 51.
2018-05-28T23:12:22.997 Info Started deserializing EliteNfcBet.Models.RootObject. Path 'Meets[2].VenueName', line 1, position 65.
2018-05-28T23:12:22.997 Verbose Could not find member 'VenueName' on EliteNfcBet.Models.RootObject. Path 'Meets[2].VenueName', line 1, position 65.
2018-05-28T23:12:22.997 Info Finished deserializing EliteNfcBet.Models.RootObject. Path 'Meets[2]', line 1, position 71.
2018-05-28T23:12:22.998 Info Finished deserializing System.Collections.Generic.List`1[[NInterpret.InterpretedObject, NInterpret.Xamarin.Droid, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]. Path 'Meets', line 1, position 72.
2018-05-28T23:12:23.009 Info Finished deserializing EliteNfcBet.Models.RootObject. Path '', line 1, position 92.
2018-05-28T23:12:23.009 Verbose Deserialized JSON: 
{
  "Meets": [
    {
      "VenueName": "O2"
    },
    {
      "VenueName": "wembly"
    },
    {
      "VenueName": "NEC"
    }
  ],
  "ErrorCode": "test"
}}

edit 3:

I've just came across this post which explains a lot! Seems like xamarin.forms has a known problem currently with reflection and so certain packages may not work correctly.

JsonConvert.SerializeObject always return {} in XamarinForms

Does anyone have any insight as to why this happens and when this will be resolved. Also a work around that I could implement so I can use debugging. Thanks.

aloisdg
  • 22,270
  • 6
  • 85
  • 105
pinman
  • 93
  • 1
  • 3
  • 13
  • 2
    Should `content` contain the string "meets"? Or should it be "Meets" ? – John Wu May 26 '18 at 00:49
  • 2
    `Meets` != `meets` – Camilo Terevinto May 26 '18 at 00:53
  • I've been trying lots of different edits to get this to work including changing the case of my class definitions etc... and nothing I've tried fixes the problem whereas. These things seem to work fine in the console application i however. Could this be project related? – pinman May 28 '18 at 21:55

1 Answers1

0
{"meets": [
{
  "VenueName": "O2"
},
{
  "VenueName": "wembly"
},
{
  "VenueName": "NEC"
}  ],  
"ErrorCode": "test"}

Your problem is that you have an object called "meets" in javascript, and in your object in C# you have "Meets". Change it to "Meets" and it should work.

You also don't need the JsonObject attribute, I believe. .NET should be able to handle the serialization from JSON automatically:

public class Meets
{
    public string VenueName { get; set; }
}

public class RootObject
{
    public List<Meets> Meets { get; set; }
    public string ErrorCode { get; set; }
}

Spend some time looking at these resources to understand why your error is occurring:

https://learn.microsoft.com/en-us/dotnet/standard/serialization/

EDIT

The above classes produces the following json:

Meets: 

{
  "VenueName": null
}

Root Object:

{
  "Meets": [
{
  "VenueName": null
}, 
{
  "VenueName": null
},
{
  "VenueName": null
}
],
  "ErrorCode": null
}
cr1pto
  • 539
  • 3
  • 13
  • Thanks for the suggestion. I have made the small change but still this does not work in my xamarin project but works fine in my console application. My json string (with escaped quotes is) "{\"Meets\":[{\"VenueName\":\"O2\"},{\"VenueName\":\"wembly\"},{\"VenueName\":\"NEC\"}],\"ErrorCode\":\"test\"}" and my class definitions match what you have defined above. – pinman May 28 '18 at 21:49