I'm new to Xamarin so please excuse me .I have a json object I'm trying to deserialize it using refit but I think the error appears because of the class is not correct
This is the json object
{
"status": true,
"message": null,
"data": [
{
"menu_id": 46,
"menu_title": "media",
"menu_parent": 0,
"menu_sort": "1",
"menu_status": "1",
"courses_count": 4,
"subCat": [
{
"menu_id": 48,
"menu_title": "media",
"menu_parent": 46,
"menu_sort": "1",
"courses_count": 0,
"menu_status": "1",
"subCat": [
{
"menu_id": 50,
"menu_title": "media",
"menu_parent": 48,
"menu_sort": "1",
"courses_count": 0,
"menu_status": "1",
"subCat": []
},
{
"menu_id": 51,
"menu_title": "media",
"menu_parent": 48,
"menu_sort": "1",
"courses_count": 0,
"menu_status": "1",
"subCat": []
}
]
},
{
"menu_id": 49,
"menu_title": "media",
"menu_parent": 46,
"menu_sort": "1",
"courses_count": 0,
"menu_status": "1",
"subCat": []
}
]
},
{
"menu_id": 47,
"menu_title": "media",
"menu_parent": 0,
"menu_sort": "2",
"menu_status": "1",
"courses_count": 2,
"subCat": []
},
{
"menu_id": 55,
"menu_title": "CS",
"menu_parent": 0,
"menu_sort": "3",
"menu_status": "1",
"courses_count": 2,
"subCat": []
}
]
}
I used json2csharp to convert the json and that's what I get
public class Datum
{
public int menu_id { get; set; }
public string menu_title { get; set; }
public int menu_parent { get; set; }
public string menu_sort { get; set; }
public string menu_status { get; set; }
public int courses_count { get; set; }
public List<object> subCat { get; set; }
}
public class RootObject
{
public bool status { get; set; }
public object message { get; set; }
public List<Datum> data { get; set; }
}
and this is the code using refit
the interface
public interface IGDGAPI
{
[Get("/category")]
Task<List<RootObject>> GetCategories();
}
the code
var apiResponce = RestService.For<IGDGAPI>("API Link Here");
var Categs = await apiResponce.GetCategories();
CategList.ItemsSource = _categs;
when I insert a breakpoint at Categs it gives me null
and this is the error message
Unhandled Exception:
Newtonsoft.Json.JsonSerializationException: Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'GDG6OCT.Models.RootObject[]' 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 'status', line 1, position 10.
This is what I used to solve it if someone came across the same problem I didn't use refit just used regular HTTP requests and NewtonSoft for Json
The Model
public class Category
{
public bool status { get; set; }
public object message { get; set; }
public IList<Datum> data { get; set; }
}
public class SubCat
{
public int menu_id { get; set; }
public string menu_title { get; set; }
public int menu_parent { get; set; }
public string menu_sort { get; set; }
public int courses_count { get; set; }
public string menu_status { get; set; }
public IList<object> subCat { get; set; }
}
public class Datum
{
public int menu_id { get; set; }
public string menu_title { get; set; }
public int menu_parent { get; set; }
public string menu_sort { get; set; }
public string menu_status { get; set; }
public int courses_count { get; set; }
public IList<SubCat> subCat { get; set; }
}
}
The API Call Request
async Task CallApi()
{
string Url = "your Link Goes Here";
HttpResponseMessage response;
string return_value = "empty";
try
{
HttpClient _client = new HttpClient();
response = await _client.GetAsync(Url);
if (response.IsSuccessStatusCode)
{
return_value = await response.Content.ReadAsStringAsync();
var categs = JsonConvert.DeserializeObject<Category>(return_value).data;
CategList.ItemsSource = categs;
}
else
{
return_value = "not successful";
}
}
catch (Exception ex)
{
return_value = (string)ex.Message + " :: " + ex.InnerException.Message;
}
}
You should try to deserialize the JSON into a JObject then access its properties by keys:
var obj = JsonConvert.DeserializeObject<JObject>("Json content as a string");
var prop1 = obj["Key1"];
var prop2 = obj["key2"]["subkey"];
You are trying to deserialize a list, however you are receiving one RootObjet.
Change this:
[Get("/category")]
Task<RootObject> GetCategories();
In my case I was not getting any feedback from my debugger, no errors just a blank object. What worked for me was to initialize the object you want to deserialize into before the Get call.
For this example (using Refit) it would be something like:
var rootObject = new RootObject();
var apiResponse = RestService.For<IGDGAPI>("API Link Here");
rootObject = await apiResponse.GetCategories();
Related
I am getting the following response from an API
"results": {
"wan1": {
"id": "wan1",
"name": "wan1",
"alias": "",
"mac": "00:00:00:00:00:00",
"ip": "102.165.223.199",
"mask": 24,
"link": true,
"speed": 1000.0,
"duplex": 1,
"tx_packets": 501850173,
"rx_packets": 307154377,
"tx_bytes": 442319826490,
"rx_bytes": 234140958061,
"tx_errors": 0,
"rx_errors": 0
},
"dmz": {
"id": "dmz",
"name": "dmz",
"alias": "",
"mac": "00:00:00:00:00:00",
"ip": "10.10.10.1",
"mask": 24,
"link": false,
"speed": 0.0,
"duplex": 0,
"tx_packets": 0,
"rx_packets": 0,
"tx_bytes": 0,
"rx_bytes": 0,
"tx_errors": 0,
"rx_errors": 0
},
"internal1": {
"id": "internal1",
"name": "internal1",
"alias": "",
"mac": "00:00:00:00:00:00",
"ip": "0.0.0.0",
"mask": 0,
"link": false,
"speed": 0.0,
"duplex": 0,
"tx_packets": 0,
"rx_packets": 0,
"tx_bytes": 0,
"rx_bytes": 0,
"tx_errors": 0,
"rx_errors": 0
}
},
"vdom": "root",
}
I have tried a few approaches to representing this JSON in c# objects
{
public Dictionary<string, List<Result>> Result { get; set; }
}
public class Result
{
public string name { get; set; }
public string ip { get; set; }
public int tx_bytes { get; set; }
public int rx_bytes { get; set; }
}
And here is the method I am using to deserialize the JSON:
var result = await client.Request()
.AppendPathSegment("api/v2/monitor/system/interface")
.SetQueryParam("access_token", token)
.GetJsonAsync<InterfaceResponse>(cancellationToken: cancellationToken);
It should be simple, but for some reason, I can't figure out the correct object representation, but when I debug I am getting null
Thanks for the help.
I can see 2 issues:
It's "results" not "result".
"results" looks like Dictionary<string, Result> not Dictionary<string, List<Result>>.
Additionally, if you're using System.Text.Json then casing may matter depending on your settings.
try this
var jsonParsed = JObject.Parse(json);
Dictionary<string,Result> results = jsonParsed["results"]
.ToObject<Dictionary<string,Result>>();
string vdom = (string)jsonParsed["vdom"];
public class Result
{
public string name { get; set; }
public string ip { get; set; }
public long tx_bytes { get; set; }
public long rx_bytes { get; set; }
//another properties
}
You need to fix the classes:
public class InterfaceResponse
{
// 1. rename or use attributes
// 2. fix type from Dictionary<string, List<Result>>
public Dictionary<string, Result> results { get; set; }
}
public class Result
{
public string name { get; set; }
public string ip { get; set; }
public long tx_bytes { get; set; } // use long, some of the values are too big to fit int
public long rx_bytes { get; set; } // use long, some of the values are too big to fit int
}
How can I turn the string fetched from the URL to a usable object? I've seen several Newtonsoft.Json examples, but none of them work with the layout of the object in the URL.
The code below is what I have so far. (the DeserializeObject part currently in the code doesn't work) due to the layout of the object.
JSON Data:
{
"totals": {
"confirmed": 4011,
"dead": 23,
"recovered": 7,
"changes": {
"newToday": 239,
"newYesterday": 378,
"diff": -139,
"deathsToday": 4,
"deathsYesterday": 5
}
},
"cases": [
{
"confirmed": 989,
"dead": 4,
"recovered": 1,
"name": "Oslo",
"countyCode": "03",
"confirmedPer1kCapita": 1.426111833700075
},
{
"confirmed": 1138,
"dead": 7,
"recovered": 1,
"name": "Viken",
"countyCode": "30",
"confirmedPer1kCapita": 0.9168805114549636
},
{
"confirmed": 284,
"dead": 2,
"recovered": 1,
"name": "Innlandet",
"countyCode": "34",
"confirmedPer1kCapita": 0.7647050904048359
},
{
"confirmed": 440,
"dead": 0,
"recovered": 3,
"name": "Vestland",
"countyCode": "46",
"confirmedPer1kCapita": 0.6912467735271338
},
{
"confirmed": 304,
"dead": 0,
"recovered": 0,
"name": "Rogaland",
"countyCode": "11",
"confirmedPer1kCapita": 0.633475865403049
},
{
"confirmed": 285,
"dead": 0,
"recovered": 0,
"name": "Trøndelag",
"countyCode": "50",
"confirmedPer1kCapita": 0.608062265575995
},
{
"confirmed": 130,
"dead": 2,
"recovered": 0,
"name": "Troms og Finnmark",
"countyCode": "54",
"confirmedPer1kCapita": 0.5342956134330138
},
{
"confirmed": 159,
"dead": 1,
"recovered": 0,
"name": "Agder",
"countyCode": "42",
"confirmedPer1kCapita": 0.5175259007066344
},
{
"confirmed": 149,
"dead": 1,
"recovered": 0,
"name": "Vestfold og Telemark",
"countyCode": "38",
"confirmedPer1kCapita": 0.3552728209138857
},
{
"confirmed": 91,
"dead": 0,
"recovered": 1,
"name": "Møre og Romsdal",
"countyCode": "15",
"confirmedPer1kCapita": 0.34308809446610217
},
{
"confirmed": 42,
"dead": 0,
"recovered": 0,
"name": "Nordland",
"countyCode": "18",
"confirmedPer1kCapita": 0.17410408937343255
}
],
"updated": {
"ts": "2020-03-28T21:23:18+01:00",
"by": "Morten Asbjørnsen",
"version": "5154"
}
}
Code:
public class Program
{
public static void Main(string[] args)
{
string Address = "https://redutv-api.vg.no/corona/v1/sheets/norway-table-overview?region=county";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Address);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
if (response.StatusCode == HttpStatusCode.OK)
{
Stream receiveStream = response.GetResponseStream();
StreamReader readStream = null;
if (String.IsNullOrWhiteSpace(response.CharacterSet))
readStream = new StreamReader(receiveStream);
else
readStream = new StreamReader(receiveStream, Encoding.GetEncoding(response.CharacterSet));
string data = readStream.ReadToEnd();
response.Close();
readStream.Close();
Console.WriteLine(data);
//No clue...
Statistic statistic = JsonConvert.DeserializeObject<Statistic>(data);
}
}
public class Statistic
{
//needs modifying.
public string confirmed.total {get;set;}
}
}
Your c# class has to have structure similar to json
(Note: I'm specifically skipping some details of deserialization for simplicity, but in short the parts of your C# class that don't match your json will be skipped - you will have default values)
Here's what you can do
Download your json from https://redutv-api.vg.no/corona/v1/sheets/norway-table-overview?region=county
Generate a c# class based on that json using some tool, for example http://json2csharp.com/ or https://www.jsonutils.com/
Rename the generated RootObject into something meaningful - this is your Statistics class
Depending on the tooling you will get a slightly different result, something similar to the code below
(Note: Some details may differ, like collection types can use array, List<T> or IList<T> depending on the tooling)
As a bonus, if you're able to use .NET Core 3x, Try the new System.Text.Json APIs - this is the recommended approach going forward, not Newtonsoft.JSON
public class Changes
{
public int newToday { get; set; }
public int newYesterday { get; set; }
public int diff { get; set; }
public int deathsToday { get; set; }
public int deathsYesterday { get; set; }
}
public class Totals
{
public int confirmed { get; set; }
public int dead { get; set; }
public int recovered { get; set; }
public Changes changes { get; set; }
}
public class Case
{
public int confirmed { get; set; }
public int dead { get; set; }
public int recovered { get; set; }
public string name { get; set; }
public string countyCode { get; set; }
public double confirmedPer1kCapita { get; set; }
}
public class Updated
{
public DateTime ts { get; set; }
public string by { get; set; }
public string version { get; set; }
}
public class RootObject
{
public Totals totals { get; set; }
public List<Case> cases { get; set; }
public Updated updated { get; set; }
}
You need an object structure in C# which matches the structure of the JSON you're downloading.
Sites like json2csharp will auto-generate a structure for you and will work with most JSON you can think of.
For the data presented by that URL when I visited it just now, it suggests this:
public class Changes
{
public int newToday { get; set; }
public int newYesterday { get; set; }
public int diff { get; set; }
public int deathsToday { get; set; }
public int deathsYesterday { get; set; }
}
public class Totals
{
public int confirmed { get; set; }
public int dead { get; set; }
public int recovered { get; set; }
public Changes changes { get; set; }
}
public class Case
{
public int confirmed { get; set; }
public int dead { get; set; }
public int recovered { get; set; }
public string name { get; set; }
public string countyCode { get; set; }
public double confirmedPer1kCapita { get; set; }
}
public class Updated
{
public DateTime ts { get; set; }
public string by { get; set; }
public string version { get; set; }
}
public class RootObject
{
public Totals totals { get; set; }
public List<Case> cases { get; set; }
public Updated updated { get; set; }
}
You can then run
RootObject obj = JsonConvert.DeserializeObject<RootObject>(data);
to deserialise it.
/* method arguments:
stream : Stream class instance
charSet: Character set (in string), default is current system encoding.
bufferSize: Buffer size, default 1024 bytes
*/
static async Task<string> readStreamAsync(Stream stream, string charSet = "", int bufferSize = 1024)
{
/* read stream to buffers */
var buffer = new byte[bufferSize];
List<byte> buffers = new List<byte>();
using (var readStream = new StreamReader(stream))
{
// read stream into buffer
var n = await readStream.ReadAsync(buffer, 0, bufferSize);
// loop buffer streaming until no more stream data
while (n > 0)
{
// populate buffer into buffer list
buffers.AddRange(new ArraySegment<byte>(buffer, 0, n).Array);
// read stream into buffer
n = await readStream.ReadAsync(buffer, 0, bufferSize);
}
}
/* return encoded string */
if (String.IsNullOrWhiteSpace(charSet))
{
// encode buffers array into default encoded string
return Encoding.Default.GetString(buffers.ToArray());
}
else
{
// encode buffers array into encoded string based on any character set
return Encoding.GetEncoding(charSet).GetString(buffers.ToArray());
}
}
/* usage: */
string data;
try
{
using (var receiveStream = response.GetResponseStream())
{
data = await readStreamAsync(receiveStream, response.CharacterSet);
}
}
finally
{
response.Close();
}
Console.WriteLine(data);
Statistic statistic = JsonConvert.DeserializeObject<Statistic>(data);
I want to serialize javascript array to object using Newtonsoft JsonConvert in C#. Any help would be appreciated.
My Javascript array object is:
[
{
"ID": 0,
"Patient_ID": 1,
"Appointment_ID": 219,
"ObservationID": "33",
"arrOption": "{\"ObservationOptionList\":[{\"Observations_Param_Option_ID\":\"77\",\"Extended_Value\":\"\"}]}"
},
{
"ID": 0,
"Patient_ID": 1,
"Appointment_ID": 219,
"ObservationID": "1",
"arrOption": "{\"ObservationOptionList\":[{\"Observations_Param_Option_ID\":\"1\",\"Extended_Value\":\"Dry\"}]}"
},
{
"ID": 0,
"Patient_ID": 1,
"Appointment_ID": 219,
"ObservationID": "8",
"arrOption": "{\"ObservationOptionList\":[{\"Observations_Param_Option_ID\":\"25\",\"Extended_Value\":\"\"}]}"
},
{
"ID": 0,
"Patient_ID": 1,
"Appointment_ID": 219,
"ObservationID": "15",
"arrOption": "{\"ObservationOptionList\":[{\"Observations_Param_Option_ID\":\"40\",\"Extended_Value\":\"\"}]}"
}
]
I assume you mean de-serialize.
Create a class to hold each Patient.
public class Patient
{
public int ID { get; set; }
public int Patient_ID { get; set; }
public int Appointment_ID { get; set; }
public string ObservationID { get; set; }
public string arrOption { get; set; }
}
Deserialize into a List of Patient.
var patients = JsonConvert.DeserializeObject<List<Patient>>(json);
Create a C# Class
class MyClass
{
public int ID {get;set;}
public int Patient_ID {get;set;}
public int Appointment_ID {get;set;}
public string ObservationID {get;set;}
public string arrOption {get;set;
}
Now use deserialize method
new JavaScriptSerializer().Deserialize<MyClass>(jsonString);
If you also want deserialize arrOption to a object you need to foreach after deserialize
I need an example how of to build a class for a JSON response with JSON.NET.
I am calling the following, that requires a class ResponseCall that I have to build:
JsonConvert.DeserializeObject<ResponseCall>(result);
My problem is that I am not sure what exactly are all the nested attributes in a class. What is "responseHeader" and the nested attributes "Status" and how do I access them?
Here is the JSON:
{
"responseHeader": {
"status": 0,
"QTime": 1801,
"params": {
"fl": "id_tlc,ccZzcucbez_tlc,ekonr_tlc,gtin_tlc,region_tlc",
"sort": "ccZzcucbez_tlc asc",
"indent": "on",
"start": "0",
"q": "indexName:b2cLMIVProdukteIndex AND ( (id_tlc:*000006757 OR gtin_tlc:6757 OR (addGtin_tlc:6757,* OR addGtin_tlc:*,6757,* OR addGtin_tlc:*,6757 ) OR ekonr_tlc:6757))",
"wt": "json",
"qt": "",
"hl": "true",
"fq": "",
"version": "2.2",
"rows": "10"
}
},
"response": {
"numFound": 1,
"start": 0,
"docs": [
{
"ekonr_tlc": "1030860",
"region_tlc": "NBST",
"ccZzcucbez_tlc": "GT EHG ERDINGER WEISSB.DKL.20X0,5L",
"id_tlc": "NBST_000000000135459003",
"gtin_tlc": "4002103010036"
}
]
},
"highlighting": {
"b2cLMIVProdukteIndex_NBST_000000000135459003": {
}
}
}
Try using this class structure:
class ResponseCall
{
[JsonProperty("responseHeader")]
public ResponseHeader ResponseHeader { get; set; }
[JsonProperty("response")]
public Response Response { get; set; }
[JsonProperty("highlighting")]
public Dictionary<string, object> Highlighting { get; set; }
}
class ResponseHeader
{
[JsonProperty("status")]
public int Status { get; set; }
[JsonProperty("QTime")]
public int QTime { get; set; }
[JsonProperty("params")]
public Dictionary<string, string> Params { get; set; }
}
class Response
{
[JsonProperty("numFound")]
public int NumFound { get; set; }
[JsonProperty("start")]
public int Start { get; set; }
[JsonProperty("docs")]
public List<Dictionary<string, string>> Docs { get; set; }
}
Then deserialize like this:
ResponseCall rc = JsonConvert.DeserializeObject<ResponseCall>(json);
Fiddle: https://dotnetfiddle.net/FdQu7U
ok so im not entirely sure how to explain this but ill give it my best shot. i have deserialisation from json working on singular objects, but when i get a list of the objects in json form, it doesnt work, and there are a few extra details outside of the singular objects when in a list of the objects.
the line of code im pretty sure is the problem is
var model = JsonConvert.DeserializeObject<DeserializedObjects.BlockList>(JObject.Parse(json).ToString());
but i cannot figure out how to solve it.
anyway.
this is where the multiple data objects in json from come from:
public static async Task<DeserializedObjects.BlockList> GetUpToTenBlocks(int height)
{
var JData = (dynamic)new JObject();
JData.height = height;
String uri = String.Concat(partialApi, "/local/chain/blocks-after");
var response = await client.PostAsync(uri, new StringContent(JData.ToString(), Encoding.UTF8, "application/json"));
var content = response.Content;
{
var json = await content.ReadAsStringAsync();
var model = JsonConvert.DeserializeObject<DeserializedObjects.BlockList>(JObject.Parse(json).ToString());
Console.WriteLine(model.AtIndex[1].difficulty);
return model;
}
}
which is deserialized to:
public class PrevBlockHash
{
public string data { get; set; }
}
public class Block
{
public int timeStamp { get; set; }
public string signature { get; set; }
public PrevBlockHash prevBlockHash { get; set; }
public int type { get; set; }
public List<object> transactions { get; set; }
public int version { get; set; }
public string signer { get; set; }
public long height { get; set; }
}
public class Datum
{
public object difficulty { get; set; }
public List<object> txes { get; set; }
public Block block { get; set; }
public string hash { get; set; }
}
public class BlockList
{
public List<Datum> AtIndex { get; set; }
}
and this is the json payload:
{
"data": [
{
"difficulty": 11763927507942,
"txes": [],
"block": {
"timeStamp": 167479,
"signature": "bb062d9b5f132b39b9e56de2413bf04928af009587446621da7afd351d
15a2ce7b5504450acf41bc3b19ab71e9bf34722005239d93f05a2318130f85118df40c",
"prevBlockHash": {
"data": "d4875ad2fc74dacfa89a13f24159d14555d3766f4fe2d708a7596f84eba88
31b"
},
"type": 1,
"transactions": [],
"version": 1744830465,
"signer": "00a30788dc1f042da959309639a884d8f6a87086cda10300d2a7c3a0e0891
a4d",
"height": 1001
},
"hash": "f70898011d7343a0823de9c9cf263de29ddf2c16bb78cea626b9af90ea7ec260"
},
{
"difficulty": 11625594628802,
"txes": [],
"block": {
"timeStamp": 167561,
"signature": "116dedf43dd06b9ca634db0e20e06cc93337cdba155bced4d843ece4cc
9a57487d58e9a34d8a0e19bf71d3b7facb15179a87767f0063ebbce7c940cd545d5f01",
"prevBlockHash": {
"data": "f70898011d7343a0823de9c9cf263de29ddf2c16bb78cea626b9af90ea7ec
260"
},
"type": 1,
"transactions": [],
"version": 1744830465,
"signer": "6ecd181da287c9ccb0075336de36427f25cbc216dc6b1f0e87e35e41a39f6
3fe",
"height": 1002
},
"hash": "77b5644c35e0d0d51f8bb967d0d92e0ddb03c4ede6632cb3b7651b7394617562"
},
{
"difficulty": 11538802895169,
"txes": [],
"block": {
"timeStamp": 167624,
"signature": "982574132fdc99b6f484acdd3f1cb5229b2bf78ad7b4e9af3d7a1873da
b987401f8bf808ff749aca70c503f490db1411b6cd89dbb0c1daa24fd580f91d3d9601",
"prevBlockHash": {
"data": "77b5644c35e0d0d51f8bb967d0d92e0ddb03c4ede6632cb3b7651b7394617
562"
},
"type": 1,
"transactions": [],
"version": 1744830465,
"signer": "26a3ac4b24647c77dc87780a95e50cb8d7744966e4569e3ac24e52c532c0c
d0d",
"height": 1003
},
"hash": "1a6d52c6317150d1839790da2c1481d714038c869842f769affbec0fdeec9861"
}
]
}
Try this:
var model = JsonConvert.DeserializeObject<DeserializedObjects.BlockList>(json);
Console.WriteLine(model.data[1].difficulty);
along with, also:
public class BlockList
{
public List<Datum> data { get; set; }
}