write data from JSON in C# - c#

I have JSON like this:
{
'surveys': [
{
'title': 'first',
'id': 100,
},
{
'title': 'second',
'id': 101,
},
{
'title': 'third',
'id': 102,
},
]
}
I want to have the output like this:
title: first
title: second
title: third
and my program in C# is like this:
WebClient client = new WebClient();
var json = client.DownloadString("http://www.test.com/api/surveys/?api_key=123");
Debug.WriteLine(json); //write all data from json
//add
var example = JsonConvert.DeserializeObject<Example>(json);
Debug.WriteLine(example.Data.Length);
class Example
{
public surveys[] Data { get; set; }
}
class surveys
{
public string title { get; set; }
public int id { get; set; }
}
I get this error:
Thrown: "Object reference not set to an instance of an object." (System.NullReferenceException) Exception Message = "Object reference not set to an instance of an object.", Exception Type = "System.NullReferenceException", Exception WinRT Data = ""
at this line: Debug.WriteLine(example.Data.Length);
where is the problem?

One problem I see is that your outer class has a property named Data, which is an array of 'surveys' objects, but your Json has a list of 'surverys' objects under the property 'surveys'. Hence the 'Data' property is never populated.
Consider the following C# class structure:
class Example
{
public survey[] surveys{ get; set; }//Data renames to surveys
}
class survey //Singular
{
public string title { get; set; }
public int id { get; set; }
}

Why can't you do so?:
JObject data = JObject.Parse(json);
foreach (var survey in data["surveys"].Children())
{
Debug.WriteLine("title: " + survey["title"]);
}

You need to use JSON.Net and use the class JsonConvert and the method DeserializeObject<T>.
If you run this:
JsonConvert.DeserializeObject<JObject>();
Then you will get back a list of de-serialized JObject objects.
Use, NuGet to download the package. I think it is called JSON.net.
Here is the weblink
WebClient client = new WebClient();
var json = client.DownloadString("http://www.test.com/api/surveys/?api_key=123");
Debug.WriteLine(json); //write all data from json
//add
var example = JsonConvert.DeserializeObject<Survey>(json);
Debug.WriteLine(example.length); // this could be count() instead.
class Survey
{
public string title { get; set; }
public int id { get; set; }
}
This should work!

Use json2csharp to generate c# classes from json.
You will also need to use Json.NET.
public class Survey
{
public string title { get; set; }
public int id { get; set; }
}
public class RootObject
{
public List<Survey> surveys { get; set; }
}
Then you can do:
var client = new WebClient();
string json = client.DownloadString(some_url);
RootObject root = JsonConvert.DeserializeObject<RootObject>(json);
foreach (Survey s in root.surveys)
{
// Do something with your survey
}
Don't forget to use Newtonsoft.Json namespace once you add a reference to it within your project.
using Newtonsoft.Json;
Edit: I have tested it using:
string json = "{'surveys': [{'title': 'first','id': 100,},{'title': 'second','id': 101,},{'title': 'third','id': 102,},]}";
instead of using the WebClient, and it works.

Related

JsonReaderException being throw trying to parse a JSON file that contains several JSON objects inside [C#]

I exported from Azure IoT Central to a Blob Storage a file containing several JSON objects (36 objects) within that same file.
The below are the first 2 lines from that file
{"applicationId":"appID","component":"thermostat1","deviceId":"usingTemControllerTemplate","enqueuedTime":"2022-03-21T15:31:38.687Z","enrichments":{},"messageProperties":{},"messageSource":"telemetry","schema":"default#v1","telemetry":{"temperature":23.2},"templateId":"urn:modelDefinition:tczx6jwcwz1:h2httvyo48g"}
{"applicationId":"appID","component":"thermostat2","deviceId":"usingTemControllerTemplate","enqueuedTime":"2022-03-21T15:31:38.703Z","enrichments":{},"messageProperties":{},"messageSource":"telemetry","schema":"default#v1","telemetry":{"temperature":16.9},"templateId":"urn:modelDefinition:tczx6jwcwz1:h2httvyo48g"}
I created 2 classes to show the heirarchy in the JSON objects. RootObject & Telemetry.
public class RootObject
{
public string applicationId { get; set; }
public string component { get; set; }
public string deviceId { get; set; }
public string enqueuedTime { get; set; }
public string messageSource { get; set; }
public string schema { get; set; }
public List<Telemetry> telemetry { get; set; }
public string templateId { get; set; }
}
public class Telemetry
{
public double temperature { get; set; }
}
I followed this answer and modeled it to my specific heirarchy and tried to make it work. However, a JsonReaderException is being thrown I run it in Visual Studio.
This is the code I'm running:
using Newtonsoft.Json;
string filePath = "~pathToFile";
RootObject rt = JsonConvert.DeserializeObject<RootObject>(filePath);
if (rt.telemetry[1].temperature == 23.2)
{
Console.WriteLine(rt.telemetry[1].temperature);
}
The JsonReaderException is being thrown on this line:
RootObject rt = JsonConvert.DeserializeObject<RootObject>(filePath);
In the below image is the message being shown:
Could someone please help me find the cause of this issue and how I could resolve it?
This file is not a list/array of objects, it's a 36 lines with each line containing json for a single object.
With this observation we can:
List<RootObject> list = new();
foreach(var line in lines.Where( l => !string.IsNullOrWhiteSpace(l)))
{
RootObject? o = JsonConvert.DeserializeObject<RootObject>(line);
if (o != null)
{
list.Add(o);
}
}
telmetry is an object, not a list so you need to also change the RootObject definition:
"telemetry": {
"temperature": 23.2
},
public class RootObject
{
...
public Telemetry telemetry { get; set; }
first of all the JSON format is wrong, it looks like this (see below) and
secondly he doesn't want to have the File path but the json (value), so you have to read it in
and what is also very important. You have 2 elements of "RootObject",
that means you have to put into a Array or List<> of RootObjects
Code:
using Newtonsoft.Json;
//reads the file and saves into a string
string jsonValue = File.ReadAllText("~pathToFile");
//Deserialize the objects and put them in a list of "RootObject".
List<RootObject> rt = JsonConvert.DeserializeObject<List<RootObject>>(jsonValue);
correct JSON format:
[
{
"applicationId": "appID",
"component": "thermostat1",
"deviceId": "usingTemControllerTemplate",
"enqueuedTime": "2022-03-21T15:31:38.687Z",
"enrichments": {},
"messageProperties": {},
"messageSource": "telemetry",
"schema": "default#v1",
"telemetry": {
"temperature": 23.2
},
"templateId": "urn:modelDefinition:tczx6jwcwz1:h2httvyo48g"
},
{
"applicationId": "appID",
"component": "thermostat2",
"deviceId": "usingTemControllerTemplate",
"enqueuedTime": "2022-03-21T15:31:38.703Z",
"enrichments": {},
"messageProperties": {},
"messageSource": "telemetry",
"schema": "default#v1",
"telemetry": {
"temperature": 16.9
},
"templateId": "urn:modelDefinition:tczx6jwcwz1:h2httvyo48g"
}
]
you have to fix json, by converting it to array of objects
var json = File.ReadAllText(filePath);
json = "[" + json.Replace("\n\r",",")+"]";
List<RootObject> lrt = JsonConvert.DeserializeObject<List<RootObject>>(json);
double[] telemetries=rt.Select(r => r.telemetry.temperature ).ToArray(); // [23.2,16.9]
double telemetry=rt.Where(t=> t.telemetry.temperature==23.2)
.Select(r =>r.telemetry.temperature ).FirstOrDefault(); //23.2
and fix class too, telemetry should be an object, not a list
public class RootObject
{
....
public Telemetry telemetry { get; set; }
}

Unable to use JSON array for Azure Function

I have below JSON input for My azure function but unable to pass it in after deserialize object
{
"name": [{
"SiteName": "Site1",
"SiteUrl": "https://site1.com/"
},
{
"SiteName": "Site2",
"SiteUrl": "https://site2.com/"
},
]
}
after deserialize I am getting count as 2 but inside array value I am not getting for deserializing using below code
string requestBody = new StreamReader(req.Body).ReadToEnd();
dynamic data = JsonConvert.DeserializeObject(requestBody);
var Root = data["name"].ToObject<List<Constant>>();
and for Constant class declared like below
class Constant
{
public Dictionary<string, string> name { get; set; }
}
Try to create class like below.
class JsonResponse
{
public List<Constant> name { get; set; }
}
class Constant
{
public string SiteName { get; set; }
public string SiteUrl { get; set; }
}
And try to Deserialize response with JsonConvert.DeserializeObject<JsonResponse>(requestBody).
string requestBody = new StreamReader(req.Body).ReadToEnd();
JsonResponse data = JsonConvert.DeserializeObject<JsonResponse>(requestBody);
var Root = data.name;
Solution 1: Deserialize as object list
The model class should be:
public class Site
{
public string SiteName { get; set; }
public string SiteUrl { get; set; }
}
And deserialize as below:
var Root = data["name"].ToObject<List<Site>>();
Sample program (Site class)
Solution 2: Deserialize as Dictionary
var Root = data["name"].ToObject<List<Dictionary<string, string>>>();
Sample program (Dictionary)

Access JSON keys in C# from ServiceNow Rest API

I am calling the ServiceNow Incidents table and pulling back one incident like this. https://mydevInstance.service-now.com/api/now/v1/table/incident?sysparm_limit=1
var client = new RestClient("https://mydevInstance.service-now.com/api/now/v1/table/incident?sysparm_limit=1");
client.Timeout = -1;
var request = new RestRequest(Method.GET);
request.AddHeader("Authorization", "Basic myAuthKey");
IRestResponse response = client.Execute(request);
The JSON it returns in RESTSharp looks like this.
{
"result": [
{
"parent": "",
"made_sla": "true",
"caused_by": "",
"watch_list": "",
"upon_reject": "cancel",
"resolved_by": {
"link": "https://mydevInstance.service-now.com/api/now/v1/table/sys_user/5137153cc611227c000bbd1bd8cd2007",
"value": "5137153cc611227c000bbd1bd8cd2007"
},
"approval_history": "",
"number": "INC0000060"
}
]
}
How do I create a C# list or array of all the Keys under result? I can't Serialize the object with JSON.Net because additional keys can be added over time.
You need to grab the sample of the JSON content, then make a C# class using the 'Paste Special' option I described.
Then you can use the JsonConvert.DeserializeObject<T> (in a nuget package by Newtonsoft) to deserialize your web service response in a C# object instance.
Here are the C# classes I generated with your JSON object unaltered:
public class Rootobject
{
public Result[] result { get; set; }
}
public class Result
{
public string parent { get; set; }
public string made_sla { get; set; }
public string caused_by { get; set; }
public string watch_list { get; set; }
public string upon_reject { get; set; }
public Resolved_By resolved_by { get; set; }
public string approval_history { get; set; }
public string number { get; set; }
}
public class Resolved_By
{
public string link { get; set; }
public string value { get; set; }
}
You use this type like this:
var json = "t-b-d"; // From Web Service call
Rootobject response = JsonConvert.DeserializeObject<Rootobject>(json);
// use the response object.
** UPDATED **
If you need a more flexible model, all JSON will deserialize into Dictionary<string, string>, but I have found that serialization / deserialization results are more reliable when the model is consistent
var response = JsonConvert.DeserializeObject<Dictionary<string,string>>(json);
Here is what does work using System.Text.Json
var incidentFields = new List<string>();
var doc = JsonDocument.Parse(json);
foreach (var o in doc.RootElement.GetProperty("result").EnumerateArray())
{
foreach (var p in o.EnumerateObject())
{
incidentFields.Add(p.Name.ToString());
}
}
I created a library that handles that by default. (You can add custom types also)
https://autodati.github.io/ServiceNow.Core/

Deserialize Json an access the result

I have this Json:
{
"UpdatePack":"updatePacks\/1585654836.pack",
"Updates":[
{
"Name":"MsgBoxEx",
"version":"1.5.14.88",
"ChangeLog":"BugFix: Form didn't resize correct.",
"Hash":"5FB23ED83693A6D3147A0485CD13288315F77D3D37AAC0697E70B8F8C9AA0BB8"
},
{
"Name":"Utilities",
"version":"2.5.1.58",
"ChangeLog":"StringManagement updated.",
"Hash":"05E6B3F521225C604662916F50A701E9783E13776DE4FCA27BE4B69705491AC5"
}
]
}
I have created 2 classes to be used to Deserialize it.
class UpdatesList
{
public string Name { get; set; }
public string Version { get; set; }
public string ChangeLog { get; set; }
public string Hash { get; set; }
}
class JsonObjectHolder
{
public string UpdatePack { get; set; }
//public Dictionary<int, MyData> { get; set; }
public Dictionary<int, UpdatesList> Updates { get; set; }
}
But when I try to access the dictionary, I keep getting Unhandled Exception: System.NullReferenceException: Object reference not set to an instance of an object. at " Console.WriteLine(jsonTest.Dict.Count);"
Am I Deserializing it wrong, or do I need to do some thing else to access the result of the dictionary?
I'm new to both C# and Json.
I hope that some one could point me in the right direction on how to handle this.
I'm using Visual Studio 2019 latest update, and .net 4.8.
Regards
/LR
You code doesn't work because 0 and 1 tokens just a properties, not the array items (you don't have square brackets [] around them). You can parse these values to desired structure manually using JObject
var json = JObject.Parse(your_json_string);
var dict = new Dictionary<int, UpdatesList>();
foreach (var item in json.Properties())
{
if (item.Value.Type == JTokenType.Object)
{
var index = int.Parse(item.Name);
var updateList = item.Value.ToObject<UpdatesList>();
dict.Add(index, updateList);
}
}
var holder = new JsonObjectHolder
{
UpdatePack = json["Updates"]?.Value<string>(),
Dict = dict
};
Update: According to OP changes made to JSON it might be deserialized even more simply
var list = json["Updates"]?.ToObject<List<UpdatesList>>();
var holder = new JsonObjectHolder
{
UpdatePack = json["UpdatePack"]?.Value<string>(),
Dict = list.Select((updatesList, index) => new { updatesList, index })
.ToDictionary(x => x.index, x => x.updatesList)
};
The main point here is that Updates is an array of items, not the key-value collection. It can be transformed into Dictionary<int, UpdatesList> using ToDictionary method from System.Linq (or just use List<UpdatesList> as is)
The exception you're getting essentially means the value is being accessed before the object is initialized.
A better, simpler and cleaner way to doing it is using NewtonSoft. (you can easily get it as a Nuget package)
example:
public class Account
{
public string Email { get; set; }
public bool Active { get; set; }
public DateTime CreatedDate { get; set; }
public IList<string> Roles { get; set; }
}
and then usage:
string json = #"{
'Email': 'james#example.com',
'Active': true,
'CreatedDate': '2013-01-20T00:00:00Z',
'Roles': [
'User',
'Admin'
]
}";
Account account = JsonConvert.DeserializeObject<Account>(json);
Console.WriteLine(account.Email);
Source: https://www.newtonsoft.com/json/help/html/DeserializeObject.htm
I don't see why you need Dictionary<int, UpdatesList> Updates, when you can easily just use List<Update> Updates, since your updates are in a JSON array.
I would model your classes like this:
public class Update
{
public string Name { get; set; }
public string Version { get; set; }
public string ChangeLog { get; set; }
public string Hash { get; set; }
}
public class RootObject
{
public string UpdatePack { get; set; }
public List<Update> Updates { get; set; }
}
You can then deserialize with:
JsonConvert.DeserializeObject<RootObject>(json);
Try it out on dotnetfiddle.net
Note: To convert JSON to C# classes, you can go to Edit -> Paste Special -> Paste JSON as Classes inside Visual Studio. Make sure you have copied the JSON to your clipboard before using it. You will get classes similar to above.
your data and the class is not compatible. if you change the string like this it would work.
change "Updates" to "UpdatePack" and add "Dict" around the dictionary items.
{
"UpdatePack":"updates\/4D1D7964D5B88E5867324F575B77D2FA.zip",
"Dict":{
"0":{
"Name":"MsgBoxEx",
"Version":"1.0.123.58",
"ChangeLog":"Bugfix:Form didn't resize correct",
"hash":"AA94556C0D2C8C73DD217974D252AF3311A5BF52819B06D179D17672F21049A6"
},
"1":{
"Name":"Utilities",
"Version":"1.5.321.87",
"ChangeLog":"StringManagement updated",
"hash":"2F561B02A49376E3679ACD5975E3790ABDFF09ECBADFA1E1858C7BA26E3FFCEF"
}
}
}

Parsing JSON data in C#

I have a JSON data as follows
{"id": "367501354973","from": {
"name": "Bret Taylor",
"id": "220439" }
which is returned by an object(result) of IDictionary[String, Object]
In my C# code:
I have made a class for storing the JSON value which is as follows
public class SContent
{
public string id { get; set; }
public string from_name { get; set; }
public string from_id { get; set; }
}
My main C# function which stores the parses the JSON data and stores the value inside the class properties is as follows:
List<object> data = (List<object>)result["data"];
foreach (IDictionary<string, object> content in data)
{
SContent s = new SContent();
s.id = (string)content["id"];
s.from_name = (string)content["from.name"];
s.from_id = (string)content["from.id"];
}
When i execute this code, i get an exception saying System cannot find the Key "from.name" and "from.id"
When i comment the two lines (s.from_name = (string)content["from.name"];s.from_id = (string)content["from.id"];) my code runs fine.
I think i am not able to refer the nested JSON data properly.
Can anyone just validate it and please tell me how to refer nested data in JSON in C#?
Thanks
I'm not sure how you are parsing the JSON string. Are you using a class in the Framework to do the deserialization?
You could use the JavaScriptSerializer Class defined in the System.Web.Script.Serialization Namespace (you may need to add a reference to System.Web.dll)
Using that class, you would write your code like this:
public class SContent
{
public string id { get; set; }
public SFrom from { get; set; }
}
public class SFrom
{
public string name { get; set; }
public string id { get; set; }
}
Then deserialization looks like this:
var json = new JavaScriptSerializer();
var result = json.Deserialize<SContent>(/*...json text or stream...*/);
See JavaScriptSerializer on MSDN. You might also want to check out this similar question.

Categories