Convert complex JSON to C# Model and downloading Data - c#

I'm trying to convert a data from a nested JSon file to C# Model, and I get this error :
Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.Generic.List`1[convert_json_to_model.Fields]' 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 'nhits', line 1, position 9.
Here is some data
{
"nhits":17933,
"parameters":{
"dataset":[
"osm-fr-bars#babel"
],
"rows":3,
"start":0,
"format":"json",
"timezone":"UTC"
},
"records":[
{
"datasetid":"osm-fr-bars#babel",
"recordid":"d95394fd7d34aa34aa9b236661bce9cda534a8ab",
"fields":{
"other_tags":"{\"cuisine\": \"tapas\", \"ref:FR:CRTA\": \"RESAQU047V506W6V\",
\"capacity\": \"14\", \"description\": \"Tous les jours \u00e0 partir de 7h\",
\"source\": \"BDOrtho IGN; Cadastre M\u00e0J 2015; Sirtaqui\", \"outdoor_seating\":
\"yes\", \"source:ref:FR:CRTA\": \"Sirtaqui\"}",
"name":"Au boin coin",
"geo_point_2d":[
44.0549704,
0.2603921
],
"phone":"+33 5 53 65 67 45"
},
"geometry":{
"type":"Point",
"coordinates":[
0.2603921,
44.0549704
]
}
Here is the link of my Json file to see all fields :
https://data.opendatasoft.com/api/records/1.0/search/?dataset=osm-fr-bars%40babel&rows=30
Here is my model after using the tool JSON to C#
public class Fields
{
[JsonProperty("other_tags")]
public string OtherTags { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("geo_point_2d")]
public List<double> GeoPoint2d { get; set; }
[JsonProperty("phone")]
public string Phone { get; set; }
}
public class Geometry
{
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("coordinates")]
public List<double> Coordinates { get; set; }
}
public class Record
{
[JsonProperty("datasetid")]
public string Datasetid { get; set; }
[JsonProperty("recordid")]
public string Recordid { get; set; }
[JsonProperty("fields")]
public Fields Fields { get; set; }
[JsonProperty("geometry")]
public Geometry Geometry { get; set; }
}
public class Root
{
[JsonProperty("records")]
public List<Record> Records { get; set; }
}
Here is the method to deserialize
static async Task Main(string[] args)
{
string url = "https://data.opendatasoft.com/api/records/1.0/search/?dataset=osm-fr-bars%40babel&rows=30";
HttpClient httpClient = new HttpClient();
try
{
var httpResponseMessage = await httpClient.GetAsync(url);
string jsonResponse = await httpResponseMessage.Content.ReadAsStringAsync();
List<Fields> myBars = JsonConvert.DeserializeObject<List<Fields>>(jsonResponse);
foreach (var bar in myBars)
{
Console.WriteLine($"{bar.Name}");
}
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}

In the main, the HTTP response is deserialized to the type List<Fields>. But the JSON rather corresponds the type Root. Try :
//List<Fields> myBars = JsonConvert.DeserializeObject<List<Fields>>(jsonResponse);
Root myBars = JsonConvert.DeserializeObject<Root>(jsonResponse);

Please organise your model well.
Fields myBars = JsonConvert.DeserializeObject<Fields>(jsonResponse);
or
Root myBars = JsonConvert.DeserializeObject<Root>(jsonResponse);
public class Root
{
[JsonProperty("records")]
public List<Record> Records { get; set; }
}
public class Record
{
[JsonProperty("datasetid")]
public string Datasetid { get; set; }
[JsonProperty("recordid")]
public string Recordid { get; set; }
[JsonProperty("fields")]
public Fields Fields { get; set; }
[JsonProperty("geometry")]
public Geometry Geometry { get; set; }
}
public class Fields
{
[JsonProperty("other_tags")]
public string OtherTags { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("geo_point_2d")]
public List<double> GeoPoint2d { get; set; }
[JsonProperty("phone")]
public string Phone { get; set; }
}
public class Geometry
{
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("coordinates")]
public List<double> Coordinates { get; set; }
}

fix your class Root and add a missed Parameters class
Root data =JsonConvert.DeserializeObject<Root>(jsonResponse);
List<Fields> myBars = data.Records.Select(f=> f.Fields).ToList();
foreach (var bar in myBars)
{
Console.WriteLine($"{bar.Name}");
}
public partial class Root
{
[JsonProperty("nhits")]
public long Nhits { get; set; }
[JsonProperty("parameters")]
public Parameters Parameters { get; set; }
[JsonProperty("records")]
public List<Record> Records { get; set; }
}
public partial class Parameters
{
[JsonProperty("dataset")]
public List<string> Dataset { get; set; }
[JsonProperty("rows")]
public long Rows { get; set; }
[JsonProperty("start")]
public long Start { get; set; }
[JsonProperty("format")]
public string Format { get; set; }
[JsonProperty("timezone")]
public string Timezone { get; set; }
}

Problem solved, i changed the loop from foreach to for with index, and i should have added this parameters :
for (int i=0;i<myBars.Records.Count();i++)
{
Console.WriteLine($"{myBars.Records[i].Fields.Name}");
}

Related

JSON DeserializeObject shows 0

hello i've got some problems in c#(xamarin)
i followed XXX tutorials about pharsing..
I only need the Value.
Can someone tell me how i solve that problem?
my Json:
{
"Header":{
"Version":5,
"Device":"80",
"Timestamp":1610066048
},
"Data":{
"Inputs":[
{
"Number":2,
"AD":"A",
"Value":{
"Value":62.0,
"Unit":"1"
}
}
]
},
"Status":"OK",
"Status code":0
}
C#
var client = new WebClient();
string json = client.DownloadString("https://XXXXXXX.com/heizung.php");
Value1 news = JsonConvert.DeserializeObject<Value1>(json);
Ausgabe.Text = news.Value;
My Class
public class Header
{
public int Version { get; set; }
public string Device { get; set; }
public int Timestamp { get; set; }
}
public class Value1
{
public string Value { get; set; }
public string Unit { get; set; }
}
public class Input
{
public int Number { get; set; }
public string AD { get; set; }
public Value1 Value { get; set; }
}
public class Data
{
public List<Input> Inputs { get; set; }
}
public class Root
{
public Header Header { get; set; }
public Data Data { get; set; }
public string Status { get; set; }
public int Statuscode { get; set; }
}
Thanks, i hope y'all have a nice day.
Deserialize Root object and track value down:
Root news = JsonConvert.DeserializeObject<Root>(json);
Ausgabe.Text = news.Data.Inputs[0].Value.Value;
You should deserialize your json as a Root class:
var root = JsonConvert.DeserializeObject<Root>(json);
After the root object is deserialized you can select whatever value you need. E.g.:
var values = root.Data.Inputs.Select(i => i.Value.Value); // string sequence

Convert Rest API JSON Response into C# object

I have a code REST API response which is json, and parsing to JObject and pulling a value from it. But i am getting the error when parsing to JObject.
Error: "Unexpected character encountered while parsing value: S. Path '', line 0, position 0."
Is there any other way to convert Json string to C# object.
I have the following code:
using Newtonsoft.Json;
using (HttpResponseMessage message = httpclient.GetAsync(folderIdURL).Result)
{
if(message.IsSuccessStatusCode)
{
var dataobjects = message.Content.ReadAsStringAsync();
//dataobjects = "{"id":"https://gbc-dev5.cloud.wc.com/DctmRest/repositories/dmgbsap_crt/","title":"DQL query results","author":[{"name":"EMC Documentum"}],"updated":"2019-05-02T15:19:52.508+00:00","page":1,"items-per-page":100,"links":[{"rel":"self","href":"https://gbc-dev5.cloud.wc.com/DctmRest/repositories/dmgbsap_crt/?dql=SELECT%20r_object_id%2cobject_name%20FROM%20dm_sysobject%20WHERE%20FOLDER%20(%27%2fgbc%2fUS%2fOSA-ATTACHMENT%2f2019%27)"}],"entries":[{"id":"https://gbc-dev5.cloud.wc.com/DctmRest/repositories/dmgbsap_crt/?dql=SELECT%20r_object_id%2cobject_name%20FROM%20dm_sysobject%20WHERE%20FOLDER%20(%27%2fgbc%2fUS%2fOSA-ATTACHMENT%2f2019%27)&index=0","title":"0b0111738011c114","updated":"2019-05-02T15:19:52.508+00:00","published":"2019-05-02T15:19:52.508+00:00","links":[{"rel":"edit","href":"https://gbc-dev5.cloud.wc.com/DctmRest/repositories/dmgbsap_crt/objects/0b0111738011c114"}],"content":{"json-root":"query-result","definition":"https://gbc-dev5.cloud.wc.com/DctmRest/repositori es/dmgbsap_crt/types/dm_sysobject","properties":{"r_object_id":"0b0111738011c114","object_name":"04"},"links":[{"rel":"self","href":"https://gbc-dev5.cloud.wc.com/DctmRest/repositories/dmgbsap_crt/objects/0b0111738011c114"}]}},{"id":"https://gbc-dev5.cloud.wc.com/DctmRest/repositories/dmgbsap_crt/?dql=SELECT%20r_object_id%2cobject_name%20FROM%20dm_sysobject%20WHERE%20FOLDER%20(%27%2fgbc%2fUS%2fOSA-ATTACHMENT%2f2019%27)&index=1","title":"0b0111738011c115","updated":"2019-05-02T15:19:52.509+00:00","published":"2019-05-02T15:19:52.509+00:00","links":[{"rel":"edit","href":"https://gbc-dev5.cloud.wc.com/DctmRest/repositories/dmgbsap_crt/objects/0b0111738011c115"}],"content":{"json-root":"query-result","definition":"https://gbc-dev5.cloud.wc.com/DctmRest/repositories/dmgbsap_crt/types/dm_sysobject","properties":{"r_object_id":"0b0111738011c115","object_name":"05"},"links":[{"rel":"self","href":"https://gbc-dev5.cloud.wc.com/DctmRest/repositories/dmgbsap_crt/objects/0b0111738011c115"}]}}]}"
JObject responseObj = JObject.Parse(dataobjects.ToString());
String id = (String)responseObj["entries" -->"content"-->"properties"-->"object_name"];
}
}
}
I am expecting the value from (String)responseObject["enteries"]["content"][" properties"]["object_name"]
JObjects are a pain. You could get a sample of the JSON response and paste it into a converter like json2csharp.com. It will generate a class for you which you can then use like so:
Generated Class:
public class MyClass
{
public string SomeProperty { get; set; }
public string AnotherProperty { get; set; }
}
Usage:
if (message.IsSuccessStatusCode)
{
var deserializedObject = JsonConvert.DeserializeObject<MyClass>(response.Content.ReadAsStringAsync().Result);
Console.WriteLine(deserializedObject.SomeProperty);
}
I would suggest to follow those steps:
You need to check that your json is actually a json, because an error says it is not. You can use online tools like this
If possible, avoid JObject and generate real classes. It is not that hard if you know the structure, and you can use another online tools
Modify your code to use classes
so you will have something like:
using System;
using Newtonsoft.Json;
namespace ConsoleApp11
{
class Program
{
public class Message
{
public Enteries enteries { get; set; }
}
public class Enteries
{
public Content content { get; set; }
}
public class Content
{
public Properties properties { get; set; }
}
public class Properties
{
public string object_name { get; set; }
}
static void Main(string[] args)
{
var input = "{\"enteries\":{\"content\":{ \"properties\":{ \"object_name\":\"your value string\"}}}}";
Message msg = JsonConvert.DeserializeObject<Message>(input);
Console.WriteLine(msg?.enteries?.content?.properties?.object_name ?? "no value");
Console.ReadKey();
}
}
}
I hope it helps 😊
Thank you so much for all the help and trips. Finally i am able to get the required value from JSON string.
Here is the Final code json2csharp.com
public class Author
{
public string name { get; set; }
}
public class Link
{
public string rel { get; set; }
public string href { get; set; }
}
public class Link2
{
public string rel { get; set; }
public string href { get; set; }
}
public class Properties
{
public string r_object_id { get; set; }
public string object_name { get; set; }
}
public class Link3
{
public string rel { get; set; }
public string href { get; set; }
}
public class Content
{
public string json_root { get; set; }
public string definition { get; set; }
public Properties properties { get; set; }
public List<Link3> links { get; set; }
}
public class Entry
{
public string id { get; set; }
public string title { get; set; }
public DateTime updated { get; set; }
public DateTime published { get; set; }
public List<Link2> links { get; set; }
public Content content { get; set; }
}
public class RootObject
{
public string id { get; set; }
public string title { get; set; }
public List<Author> author { get; set; }
public DateTime updated { get; set; }
public int page { get; set; }
public int items_per_page { get; set; }
public List<Link> links { get; set; }
public List<Entry> entries { get; set; }
}
Using Newtonsoft.Json
First get the list of entries from the responseObj. Then loop each entries and use LINQ to JSON to get values by property name or index.
You can use Item[Object] index on JObject/JArray and then cast the returned JValue to the type you want
JObject responseObj = JObject.Parse(dataobjects.ToString());
// get JSON result objects into a list
IList<JToken> entries = responseObj ["entries"].Children().ToList();
foreach(JToken entry in entries)
{
string object_name = (string) entry["content"]["properties"]["object_name"];
}

Parse JSON using c#

I have been using NewtonSoft JSON Convert library to parse and convert JSON string to C# objects. I am unable to convert it into C# object because I cant make a C# class out of this JSON string.
Here is the JSON string:
{
"appId":"G9RNVJYTS6SFY",
"merchants":{
"RZX9YMHSMP6A8":[
{
"objectId":"A:G9RNVJYTS6SFY",
"type":"DELETE",
"ts":1522736100111
}
],
"MNOVJT2ZRRRSC":[
{
"objectId":"A:G9RNVJYTS6SFY",
"type":"CREATE",
"ts":1522736100111
}
]
},
... and so on
}
The names RZX9YMHSMP6A8 and MNOVJT2ZRRRSC change from request to request
USED
var dict = JsonConvert.DeserializeObject<Dictionary<string, RootObject>>(JSON);
I got exception while this line is executed
Error converting value "G9RNVJYTS6SFY" to type 'RootObject'. Path 'appId', line 1, position 24.
public class Merchant
{
public string objectId
{
get;
set;
}
public string type
{
get;
set;
}
public long ts
{
get;
set;
}
}
public class Merchants
{
public List<Merchant> merchant
{
get;
set;
}
}
public class RootObject
{
public string appId
{
get;
set;
}
public Merchants merchants
{
get;
set;
}
}
You can convert this json to c# class structure using a Dictionary to hold the merchants (where the ID is the string key):
public class RootObject
{
public string AppId { get; set; }
public Dictionary<string, List<ChildObject>> Merchants { get; set; }
}
public class ChildObject
{
public string ObjectId { get; set; }
public string Type { get; set; }
public long Ts { get; set; }
}
You can then loop over the childobjects like so:
foreach (var kvp in rootObject.Merchants)
{
var childObjects = kvp.Value;
foreach (var childObject in childObjects) {
Console.WriteLine($"MerchantId: {kvp.Key}, ObjectId: {childObject.ObjectId}, Type: {childObject.Type}");
}
}

Unable to deserialize JSON in c#

I am getting the below JSON in response from a REST API.
{
"data":{
"id":123,
"zoneid":"mydomain.com",
"parent_id":null,
"name":"jaz",
"content":"172.1 6.15.235",
"ttl":60,
"priority":null,
"type":"A",
"regions":[
"global"
],
"system_record":false,
"created_at":"2017-09-28T12:12:17Z",
"updated_at":"2017-09-28T12:12:17Z"
}
}
and trying to resolve using below code but that doesn't result in a correctly deserialized type.
var model = JsonConvert.DeserializeObject<ResponseModel>(response);
below is a class according the field I received in JSON response.
public class ResponseModel
{
public int id { get; set; }
public string zone_id { get; set; }
public int parent_id { get; set; }
public string name { get; set; }
public string content { get; set; }
public int ttl { get; set; }
public int priority { get; set; }
public string type { get; set; }
public string[] regions { get; set; }
public bool system_record { get; set; }
public DateTime created_at { get; set; }
public DateTime updated_at { get; set; }
}
What is missing?
You're missing a wrapper class.
public class Wrapper
{
public ResponseModel data {get;set}
}
and then do:
var model = JsonConvert.DeserializeObject<Wrapper>(response).data;
to get the instance of your ResponseModel out the data property.
You can deduct this from your json:
{ "data":
{ "id":123, /*rest omitted */ }
}
The type that will receive this JSON needs to have a property named data. The suggested Wrapper class acts as that type.
According to json2csharp website, your model seems to be incorrect. Try this one :
public class ResponseModel
{
public int id { get; set; }
public string zoneid { get; set; }
public object parent_id { get; set; }
public string name { get; set; }
public string content { get; set; }
public int ttl { get; set; }
public object priority { get; set; }
public string type { get; set; }
public List<string> regions { get; set; }
public bool system_record { get; set; }
public DateTime created_at { get; set; }
public DateTime updated_at { get; set; }
}
public class RootObject
{
public ResponseModel data { get; set; }
}
Here a cool trick you can do in Visual Studio 2015-2017 where it generates the the correct class if you just copy the JSON (ctrl + c).
You need to create a new class in visual studio and once inside the class go to Edit menu -> Paste special -> paste JSON As Classes.
Steps to generate json class
This will generate the C# object for that json for you and save you all the hassle :)
Your model does not match your response - it matches the data property. Simply wrap another object round it
public class ResponseData
{
public ResponseModel Data {get; set; {
}
and then
var model = JsonConvert.DeserializeObject<ResponseData>(response);

API to Object (with array) in C#

I'm returning data from transportapi.com & loading it into an object, but the data within the json array isn't being included.
The json returned is:
{
"atcocode": "490012745J",
"smscode": "47889",
"request_time": "2016-11-11T22:10:42+00:00",
"departures": {
"55": [
{
"mode": "bus",
"line": "55",
"line_name": "55",
"direction": "Bakers Arms",
"operator": "TFL",
"date": null,
"expected_departure_date": "2016-11-11",
"aimed_departure_time": null,
"expected_departure_time": "22:19",
"best_departure_estimate": "22:19",
"source": "Countdown instant"
}
]
}
}
Controller code:
var source = "http://transportapi.com/v3/uk/bus/stop/490012745J/live.json?api_key=[key]&app_id=[appid]";
Uri sourceUri = new Uri(source);
System.Net.Http.HttpClient sourceClient = new System.Net.Http.HttpClient();
System.Net.Http.HttpResponseMessage sourceResponse = await sourceClient.GetAsync(sourceUri);
var sourceArray = await sourceResponse.Content.ReadAsStringAsync();
var selections = JsonConvert.DeserializeObject<RootObject>(sourceArray);
Model class:
public class BusDepartures
{
public string mode { get; set; }
public string line { get; set; }
public string line_name { get; set; }
public string direction { get; set; }
public string busoperator { get; set; }
public object date { get; set; }
public string expected_departure_date { get; set; }
public object aimed_departure_time { get; set; }
public string expected_departure_time { get; set; }
public string best_departure_estimate { get; set; }
public string source { get; set; }
}
public class Departures
{
// First attempt, use BusDepartures object.
//public List<BusDepartures> BusDepartures { get; set; }
// Second attempt (as "55" is an array), use array, then convert to object later.
public string[] routes { get; set; }
}
public class RootObject
{
public string atcocode { get; set; }
public string smscode { get; set; }
public string request_time { get; set; }
public Departures departures { get; set; }
}
Within the Departures class I did try and create a BusDepartures object to store the details of the departures, but I wondered whether, as it is an array, I should use the routes array instead? However when stepping through the code, the BusDepartures object (when it was uncommented) and the routes array were both null.
Any ideas? What am I missing?
Update:
Thanks to botond.botos for the answer. I amended my class to
public class RootObject
{
public string atcocode { get; set; }
public string smscode { get; set; }
public string request_time { get; set; }
public IDictionary<int, IEnumerable<BusDepartures>> departures { get; set; }
}
and it worked.
You won't need the Departures class, and try to change the RootObject class the following way:
public class RootObject
{
public string atcocode { get; set; }
public string smscode { get; set; }
public string request_time { get; set; }
public IDictionary<int, IEnumerable<BusDepartures>> departures { get; set; }
}
I'm pretty sure your trying to map the property name "55" to a non-existent c# property. Either modify the json (which i'm assuming you can't) or use a more generic property to handle the departures.
I'm thinking maybe something like a generic Dictionary(Of int, List(of Departure)) .... which is of course vb and I'm going to guess at new Dictionary<#int, List>() in c# ? :)
public class departures {
public Dictionary<int, List<Departure>> BusDepartures {get; set; }
}

Categories