Rokesh
Rokesh

Reputation: 37

Deserialize JSON object xamarin C#

I am getting the following error in Xamarin cross platform while deserializing the JSON Object. I have tried to do it with dictionary. But, everything gives me the same exception.

Newtonsoft.Json.JsonSerializationException: Cannot deserialize the current JSON object (e.g. {\"name\":\"value\"}) into type 'System.Collections.Generic.List`1[NBStudents.Models.jsonobjectclass+User]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.
To fix this error either change the JSON to a JSON array (e.g. [1,2,3]) or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List<T>) that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object.Path 'data.name', line 4, position 11.

My JSON Object Class:

public class jsonobjectclass
{
    public class User
    {
        public string name { get; set; }
        public string email { get; set; }
        public string phone { get; set; }
        public string current_group { get; set; }
        public List<UserGroups> user_groups { get; set; }
    }

    public class UserGroups
    {
        [JsonProperty("10")]
        public string Student { get; set; }
        [JsonProperty("15")]
        public string Tutor { get; set; }
        [JsonProperty("11")]
        public string Parent { get; set; }
    }

    public class Token
    {
        public string access_token { get; set; }
        public int expires_in { get; set; }
        public string token_type { get; set; }
        public string scope { get; set; }
        public string refresh_token { get; set; }
        public string error { get; set; }
    }


    public class UserResponse
    {
        public string msg { get; set; }
        public List<User> data { get; set; }
        public bool error { get; set; }
    }
}

My Code to Deserialize JSON:

public static async Task<jsonobjectclass.UserResponse> UserRetrievalTask(string token, string apiUrl)
    {
        var jsonObject = new jsonobjectclass.UserResponse();
        string readHttpResponse;

        using (var httpClient = new HttpClient())
        {
            using (var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, apiUrl))
            {
                httpRequestMessage.Headers.Add("Authorization", "Bearer " + token); 
                using (var httpResponse = await httpClient.SendAsync(httpRequestMessage).ConfigureAwait(false))
                {
                    readHttpResponse = await httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false);
                    var jObject = JObject.Parse(readHttpResponse);
                    try
                    {
                        jsonObject = JsonConvert.DeserializeObject<jsonobjectclass.UserResponse>(jObject.ToString());
                    }
                    catch(Exception ex)
                    {
                        string excep = ex.ToString();
                        readHttpResponse = excep;
                    }
                }
            }
        }
        return jsonObject;
    }

My JSON String:

{{
  "msg": null,
  "data": {
  "name": "geoit",
  "email": "[email protected]",
  "phone": null,
  "current_group": "11",
  "user_groups": {
   "11": "Parent"
   }
},
"error": false
}}

Please Help me to solve this.

Thanks, Rokesh

Upvotes: 1

Views: 1333

Answers (3)

ste-fu
ste-fu

Reputation: 7482

You have mismatch between the string and the object you are trying to deserialize into. The data object is not an array and there is an additional nested object which is not named in the JSON separately containing the msg field and the user data, but the error field is not part of that object:

As the comments have pointed out the JSON is not valid as is, so if you have control of the source I would fix that.

If not you could implement a reader and parse it as token by token, something like this:

using (var response = await client.GetAsync(_url, HttpCompletionOption.ResponseHeadersRead))
using (var stream = await response.Content.ReadAsStreamAsync())
using (var streamReader = new StreamReader(stream))
using (var reader = new JsonTextReader(streamReader))
{

    var serializer = new JsonSerializer();      

    while (reader.Read())
    {
        switch (reader.TokenType)
        {
            case JsonToken.Start:
            // code to handle it
            break;
            case JsonToken.PropertyName:
            // code to handle it
            break;

            // more options 
        }
    }       
}

although this approach is more fragile. You can take a look at The JSON.Net JsonToken docs for more info.

Based on your comment and using https://jsonlint.com/ the response string

"{\"msg\":null,\"data\":{\"name\":\"geoit\",\"email\":\"roke‌​[email protected]\",\"phon‌​e\":null,\"current_g‌​roup\":\"11\",\"user‌​_groups\":{\"11\":\"‌​Parent\"}},\"error\"‌​:false}"

is actually valid JSON, but the object is a little bizarre. I think it looks something like this in C#

public class UserGroup
{
    public string 11 { get; set; }
}

public class UserData {
    public string name  { get; set; }
    public string email  { get; set; }
    public string phone  { get; set; }
    public string current_group  { get; set; }
    public UserGroup user_groups  { get; set; }
}

public class ResponseObject
{    
    public string msg { get; set; }
    public UserData data  { get; set; }
    public bool error  { get; set; }
}

Upvotes: 1

Jins Peter
Jins Peter

Reputation: 2469

Aplogies for the misleading answer earlier. The object you need to make array is the 'data' property of the response JSON. You have to get it from the server side as your Domainmodal List<User>. You should get a better understanding from this fiddle

readHttpResponse can be

    {
          "msg": null,
          "data": [{
          "name": "geoit",
          "email": "[email protected]",
          "phone": null,
          "current_group": "11",
          "user_groups": {
           "11": "Parent"
           }
        }],
        "error": false
   }
 and

readHttpResponse.data needs to be array

[{
              "name": "geoit",
              "email": "[email protected]",
              "phone": null,
              "current_group": "11",
              "user_groups": {
               "11": "Parent"
               }
            }]

Upvotes: 0

Qiqo
Qiqo

Reputation: 64

It should be an array the opening and closing brackets should be square brackets:

[

{ "msg": null,"data":

[ { "name": "geoit", "email": "[email protected]", "phone": null, "current_group": "11", "user_groups":

[{ "11": "Parent" } ]

} ],

"error": false }

]

Also in your code, you dont need var jObject = JObject.Parse(readHttpResponse); since the readHttpResponse is already a JSON string which you can deserialzie into an object.

Upvotes: 0

Related Questions