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": "rokesh#geoit.in",
"phone": null,
"current_group": "11",
"user_groups": {
"11": "Parent"
}
},
"error": false
}}
Please Help me to solve this.
Thanks,
Rokesh
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\":\"rokesh#geoit.in\",\"phone\":null,\"current_group\":\"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; }
}
It should be an array the opening and closing brackets should be square brackets:
[
{ "msg": null,"data":
[ {
"name": "geoit",
"email": "rokesh#geoit.in",
"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.
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": "rokesh#geoit.in",
"phone": null,
"current_group": "11",
"user_groups": {
"11": "Parent"
}
}],
"error": false
}
and
readHttpResponse.data needs to be array
[{
"name": "geoit",
"email": "rokesh#geoit.in",
"phone": null,
"current_group": "11",
"user_groups": {
"11": "Parent"
}
}]
Related
I am trying to use an RESTFUL API for an application we use internally. One call to the API returns the following JSON:
{
"operation": {
"name": "GET RESOURCES",
"result": {
"status": "Success",
"message": "Query was successful"
},
"totalRows": 2,
"Details": [{
"RESOURCE DESCRIPTION": "Windows",
"RESOURCE TYPE": "Windows",
"RESOURCE ID": "101",
"RESOURCE NAME": "WINDOWSPC",
"NOOFACCOUNTS": "1"
}, {
"RESOURCE DESCRIPTION": "Ubuntu",
"RESOURCE TYPE": "Linux",
"RESOURCE ID": "808",
"RESOURCE NAME": "UBUNTUPC",
"NOOFACCOUNTS": "2"
}]
}
}
Using json.net I deseralize the json and check the stats with the following lines:
dynamic json = JsonConvert.DeserializeObject(response);
var status = json.operation.result.status.Value;
Next I want to get each value of each of the "Details" returned, but I cannot figure out how. I first tried getting the Details only with this:
var resourceList = json.operation.Details
Which works, but I cannot iterate over this to get just the "RESOURCE ID" and "RESOURCE NAME" for example.
I cannot use .Children() either, but when I hover over the resourceList there is a ChildrenTokens which seems to be what I want, but I cannot get at that in my code.
I also tried using resourceList as a DataSet as per their example but it throws an exception.
Can someone see what I am doing wrong..... I am not familiar with parsing JSON in C#
You can use Json.Linq for that and parse a response into JObject, then iterate it foreach loop. It's possible, since Details is an array and JObject implements IDictionary<string, JToken> and IEnumerable<KeyValuePair<string, JToken>>
var jObject = JObject.Parse(response);
foreach (var detail in jObject["operation"]["Details"])
{
var description = detail["RESOURCE DESCRIPTION"].Value<string>();
//other properties
}
Here's an example using the JObject class instead of dynamic
JObject json = JObject.Parse(response);
string status = json["operation"]["result"]["status"].Value<string>();
foreach (JToken resource in json["operation"]["Details"])
{
string id = resource["RESOURCE ID"].Value<string>();
string name = resource["RESOURCE NAME"].Value<string>();
}
It is as simple as this:
Your Model classes would look like:
public class Result
{
public string status { get; set; }
public string message { get; set; }
}
public class Detail
{
[JsonProperty("RESOURCE DESCRIPTION")]
public string ResourceDescription { get; set; }
[JsonProperty("RESOURCE TYPE")]
public string ResourceType { get; set; }
[JsonProperty("RESOURCE ID")]
public string ResourceId { get; set; }
[JsonProperty("RESOURCE NAME")]
public string ResourceName { get; set; }
[JsonProperty("NOOFACCOUNTS")]
public string NoOfAccounts { get; set; }
}
public class Operation
{
public string name { get; set; }
public Result result { get; set; }
public int totalRows { get; set; }
public List<Detail> Details { get; set; }
}
public class RootObject
{
public Operation operation { get; set; }
}
To de-serialize:
var json = JsonConvert.DeserializeObject<RootObject>(response);
To access a property:
var name=json.operation.name
To access your Details:
foreach(var item in json.operation.Details)
{
var myresourcename=item.ResourceName;
//So on
}
New to both C# and to using JSON. Trying to make something that works with some JSON from a web API in the following format. Would like to loop through and store the secondUser_id and and the status for later use.
{
"user_list": [
{
"user_id": "12345678910",
"secondUser_id": "5428631729616515697",
"member_since": "1521326679",
"member_since_date": "2018-03-32",
"function": "test",
"rank_int": "1",
"status": "0"
},
{
"user_id": "11345638910",
"secondUser_id": "5428631729616515697",
"member_since": "1521326679",
"member_since_date": "2018-03-32",
"function": "test",
"rank_int": "1",
"status": "0"
},
{
"user_id": "13452578910",
"secondUser_id": "12390478910",
"member_since": "12316578910",
"member_since_date": "2018-03-32",
"function": "test",
"rank_int": "1",
"status": "0"
}
],
"returned": 3
}
string jsonUrl = GetJSON("url");
JObject UsersJObject = JObject.Parse(jsonUrl);
JToken user = UsersJObject["user_list"].First["secondUser_id"];
Console.WriteLine("User ID: " + user);
This will get the first entry but I'm not sure what to use for a enumerator?
try something like this:
foreach (var obj in UsersJObject["user_list"] as JArray)
{
Console.WriteLine(obj["secondUser_id"]);
}
You can iterate over elements of a JArray, and user_list will be of that type, cast it and you can iterate it in a foreach loop.
I will recommend you to use JsonConvert.DeserializeObject<T>.
This can help you to use objects easily
public class UserList
{
public string user_id { get; set; }
public string secondUser_id { get; set; }
public string member_since { get; set; }
public string member_since_date { get; set; }
public string function { get; set; }
public string rank_int { get; set; }
public string status { get; set; }
}
public class JsonData
{
public List<UserList> user_list { get; set; }
public int returned { get; set; }
}
Use like this.
string jsonUrl = GetJSON("url");
JsonData UsersJObject = JsonConvert.DeserializeObject<JsonData>(jsonUrl);
foreach (var obj in UsersJObject.user_list)
{
Console.WriteLine(obj.secondUser_id);
}
This is my json string :
{"loginAccounts": [
{
"name": "abc",
"accountId": "123456",
"baseUrl": "https://abc.defghi.com/test/t12/remark/123456",
"isDefault": "true",
"userName": "Ceilina James",
"userId": "7c5bat57-850a-5c93-39eb-2015ai9o8822",
"email": "abc#test.com",
"siteDescription": ""
}
]}
I need "baseUrl" value. How to find it in the C# ?
You could use a JSON serializer such as the JavaScriptSerializer class to deserialize this JSON string to a C# class and then extract the required value. For example you could have the following model:
public class SomeModel
{
public LoginAccount[] LoginAccounts { get; set; }
}
public class LoginAccount
{
public string Name { get; set; }
public string AccountId { get; set; }
public string BaseUrl { get; set; }
public string IsDefault { get; set; }
...
}
and then:
string json = "... your JSON string comes here ...";
var serializer = new JavaScriptSerializer();
string json = ...
var model = (SomeModel)serializer.Deserialize(json);
foreach (var account in model.LoginAccounts)
{
string baseUrl = account.BaseUrl;
...
}
Using Json.Net
foreach (var acc in JObject.Parse(json)["loginAccounts"])
{
Console.WriteLine(acc["baseUrl"]);
}
Given:
The classes:
public class Venue
{
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("location")]
public Location Location { get; set; }
}
public class Location
{
public long Lat { get; set; }
public long Lng { get; set; }
public int Distance { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Country { get; set; }
}
public class Response
{
private List<Venue> _venues;
[JsonProperty("venues")]
public List<Venue> Venues
{
get { return _venues ?? (_venues = new List<Venue>()); }
set { _venues = value; }
}
}
And a response request:
{
"meta":{
"code":200
},
"response":{
"venues":[
{
"id":"4f96a5aee4b01cb74e4dc3c6",
"name":"Centro",
"contact":{
},
"location":{
"address":"Centro",
"lat":-21.256906640441052,
"lng":-48.31978432813259,
"distance":185,
"city":"Jaboticabal",
"state":"SP",
"country":"Brazil",
"cc":"BR"
},
"canonicalUrl":"https:\/\/foursquare.com\/v\/centro\/4f96a5aee4b01cb74e4dc3c6",
"categories":[
{
"id":"4f2a25ac4b909258e854f55f",
"name":"Neighborhood",
"pluralName":"Neighborhoods",
"shortName":"Neighborhood",
"icon":{
"prefix":"https:\/\/foursquare.com\/img\/categories_v2\/parks_outdoors\/neighborhood_",
"suffix":".png"
},
"primary":true
}
],
"verified":false,
"restricted":true,
"stats":{
"checkinsCount":1106,
"usersCount":86,
"tipCount":0
},
"specials":{
"count":0,
"items":[
]
},
"hereNow":{
"count":0,
"groups":[
]
},
"referralId":"v-1376511204"
},
{
"id":"4c38b0b21a38ef3b56b39221",
"name":"Ice by Nice",
"contact":{
},
"location":{
"address":"Jaboticabal Shopping",
"lat":-21.25513775,
"lng":-48.32320093,
"distance":253,
"city":"Jaboticabal",
"state":"SP",
"country":"Brazil",
"cc":"BR"
},
"canonicalUrl":"https:\/\/foursquare.com\/v\/ice-by-nice\/4c38b0b21a38ef3b56b39221",
"categories":[
{
"id":"4bf58dd8d48988d1c9941735",
"name":"Ice Cream Shop",
"pluralName":"Ice Cream Shops",
"shortName":"Ice Cream",
"icon":{
"prefix":"https:\/\/foursquare.com\/img\/categories_v2\/food\/icecream_",
"suffix":".png"
},
"primary":true
}
],
"verified":false,
"restricted":true,
"stats":{
"checkinsCount":656,
"usersCount":309,
"tipCount":15
},
"specials":{
"count":0,
"items":[
]
},
"hereNow":{
"count":2,
"groups":[
{
"type":"others",
"name":"Other people here",
"count":2,
"items":[
]
}
]
},
"referralId":"v-1376511204"
}
]
}
}
When using JSON.NET like so:
Response response = JsonConvert.DeserializeObject<Response>(jsonString);
The deserialized response object has a empty list of venues, What am I doing wrong?
Thanks
There's a bit of a mismatch in what you're trying to deserialize and the class you have defined to deserialize into. You unfortunately need yet another layer of indirection. Note the response has;
// theres an outer object here which contains response
{
"meta":{ "code":200 },
"response":{
// you're trying to deserialize this, but it's not the entire response, it's a property of an anonymous object
}
}
So if I make a new class;
public class ResponseWrapper
{
public object meta;
public Response response;
}
And instead do;
ResponseWrapper response = JsonConvert.DeserializeObject<ResponseWrapper>(jsonString);
Then it will work.
Note that when you're deserializing using json.NET you have to define a structure that exactly matches the json. In this case you're leaving out the outer most object. It is kind of an annoyance and leads to a lot of code like what I just wrote but that's just the way it goes sometimes.
I've been playing with this for the past few days and I'm hoping someone could shed some light on what the issue could be.
I have this custom object that I created:
public class WorldInformation
{
public string ID { get; set; }
public string name { get; set; }
}
and this JSON data:
string world = "[{\"id\":\"1016\",\"name\":\"Sea of Sorrows\"}, {\"id\":\"1008\",\"name\":\"Jade Quarry\"},{\"id\":\"1017\",\"name\":\"Tarnished Coast\"},{\"id\":\"1006\",\"name\":\"Sorrow's Furnace\"},{\"id\":\"2014\",\"name\":\"Gunnar's Hold\"}]";
and I can sucessfully save the data in my custom object by deserializing it:
List<WorldInformation> worlds = JsonConvert.DeserializeObject<List<WorldInformation>>(world);
But...
When I create a custom object like this
public class EventItems
{
public string World_ID { get; set; }
public string Map_ID { get; set; }
public string Event_ID { get; set; }
public string State { get; set; }
}
and have JSON data like this:
string eventItem = "{\"events\":[{\"world_id\":1011,\"map_id\":50,\"event_id\":\"BAD81BA0-60CF-4F3B-A341-57C426085D48\",\"state\":\"Active\"},{\"world_id\":1011,\"map_id\":50,\"event_id\":\"330BE72A-5254-4036-ACB6-7AEED05A521C\",\"state\":\"Active\"},{\"world_id\":1011,\"map_id\":21,\"event_id\":\"0AC71429-406B-4B16-9F2F-9342097A50AD\",\"state\":\"Preparation\"},{\"world_id\":1011,\"map_id\":21,\"event_id\":\"C20D9004-DF6A-4217-BF25-7D6B5788A94C\",\"state\":\"Success\"}]}";
I get an error when I try to deserialize it
List<EventItems> events = JsonConvert.DeserializeObject<List<EventItems>>(eventItem);
The error message I get is:
Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.Generic.List`1[WebApplication1.EventItems]' 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) 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 'events', line 1, position 10.
Unforturnately there isn't a way to specify the root Json element like the XmlSerializer.
See How to deserialize JSON array with "root" element for each object in array using Json.NET?
public class EventItems
{
public EventItems()
{
Events = new List<EventItem>();
}
public List<EventItem> Events { get; set; }
}
public class EventItem
{
public string World_ID { get; set; }
public string Map_ID { get; set; }
public string Event_ID { get; set; }
public string State { get; set; }
}
Usage:
string eventItem = "{\"events\":[{\"world_id\":1011,\"map_id\":50,\"event_id\":\"BAD81BA0-60CF-4F3B-A341-57C426085D48\",\"state\":\"Active\"},{\"world_id\":1011,\"map_id\":50,\"event_id\":\"330BE72A-5254-4036-ACB6-7AEED05A521C\",\"state\":\"Active\"},{\"world_id\":1011,\"map_id\":21,\"event_id\":\"0AC71429-406B-4B16-9F2F-9342097A50AD\",\"state\":\"Preparation\"},{\"world_id\":1011,\"map_id\":21,\"event_id\":\"C20D9004-DF6A-4217-BF25-7D6B5788A94C\",\"state\":\"Success\"}]}";
var items = JsonConvert.DeserializeObject<EventItems>(eventItem);
In first case your json is array of objects, so deserialization into a list of your class type succeeds.
In second case, your json is an object, and its "events" property is set to an array of objects, so it cannot be deserialized into a list.
What you may do, is change your class declaration:
public class EventItem
{
public string World_ID { get; set; }
public string Map_ID { get; set; }
public string Event_ID { get; set; }
public string State { get; set; }
}
public class EventItems
{
public EventItem[] Events { get; set; }
}
And deserialize it:
EventItems events = JsonConvert.DeserializeObject<EventItems>(eventItem);
Simply remove the object events from the 2nd JSON string:
string eventItem = "[{\"world_id\":1011,\"map_id\":50,\"event_id\":\"BAD81BA0-60CF-4F3B-A341-57C426085D48\",\"state\":\"Active\"},{\"world_id\":1011,\"map_id\":50,\"event_id\":\"330BE72A-5254-4036-ACB6-7AEED05A521C\",\"state\":\"Active\"},{\"world_id\":1011,\"map_id\":21,\"event_id\":\"0AC71429-406B-4B16-9F2F-9342097A50AD\",\"state\":\"Preparation\"},{\"world_id\":1011,\"map_id\":21,\"event_id\":\"C20D9004-DF6A-4217-BF25-7D6B5788A94C\",\"state\":\"Success\"}]";
It seems that your JSON string is not the same in both examples.
On the first example, you're using a simple JSON array:
[
{
"id": "1016",
"name": "Sea of Sorrows"
},
{
"id": "1008",
"name": "Jade Quarry"
},
{
"id": "1017",
"name": "Tarnished Coast"
},
{
"id": "1006",
"name": "Sorrow's Furnace"
},
{
"id": "2014",
"name": "Gunnar's Hold"
}
]
And on the second example, you're assigning your array to an object (events):
{
"events":
[
{
"world_id": 1011,
"map_id": 50,
"event_id": "BAD81BA0-60CF-4F3B-A341-57C426085D48",
"state": "Active"
},
{
"world_id": 1011,
"map_id": 50,
"event_id": "330BE72A-5254-4036-ACB6-7AEED05A521C",
"state": "Active"
},
{
"world_id": 1011,
"map_id": 21,
"event_id": "0AC71429-406B-4B16-9F2F-9342097A50AD",
"state": "Preparation"
},
{
"world_id": 1011,
"map_id": 21,
"event_id": "C20D9004-DF6A-4217-BF25-7D6B5788A94C",
"state": "Success"
}
]
}