Deserializing Json to list of objects in C# with Newtonsoft - c#

So I am struggeling to parse the following JSON string. Even after researching many questions here on StackOverflow.
Json
[
{
"text": {
"0": "Element 1"
},
"cascade": [],
"val": "1"
},
{
"text": {
"0": "Element 2"
},
"cascade": [],
"val": "2"
},
{
"text": {
"0": "Element 3"
},
"cascade": [],
"val": "3"
},
{
"text": {
"0": "Unknown"
},
"cascade": [],
"val": "0"
}
]
The class I created for this looks like this:
Options.cs
using System.Collections.Generic;
namespace App.Models
{
public class Options
{
public ICollection<IDictionary<string, string>> text { get; set; }
public List<string> cascade { get; set; }
public string val { get; set; }
}
}
For running the deserialization I've written the following line:
List<Options> optionList = JsonConvert.DeserializeObject<List<Options>>(inputString);
I'm getting the following exceptions when I try to run the code:
Newtonsoft.Json.JsonSerializationException: Timeout exceeded getting exception details

You problem is reading the "text" object.
From you sample, it contains key/value pairs of string type both.
There is no reason to use ICollection there, but only Dictionary<string, string>
public class Options
{
public Dictionary<string, string> text { get; set; }
public List<string> cascade { get; set; }
public string val { get; set; }
}
Update:
Since your sample JSON does not include data about the cascade member (only an empty array), it might be safe declaring it as a list of objects List<object>.

Related

I want to convert api json data to value c#

Hi i'm newbie in c# dev and i'm not good at english i try to get value from json but it gives error [https://www.tutorialsteacher.com/articles/convert-json-string-to-object-in-csharp]
If anyone can help me with simple code I would be very grateful.
{
"result": [{
"company": "Server",
"results": [{
"name": "Server-01",
"access": ["8.8.8.8:443", "1.1.1.1:443"],
"is_ok": "0"
}, {
"name": "Server-02",
"access": ["8.8.8.8:443", "1.1.1.1:443"],
"is_ok": "0"
}, {
"name": "Server-03",
"access": ["8.8.8.8:443", "1.1.1.1:443"],
"is_ok": "1"
}, {
"name": "Server-04",
"access": ["8.8.8.8:443", "1.1.1.1:443"],
"is_ok": "0"
}, {
"name": "Server-05",
"access": ["8.8.8.8:443", "1.1.1.1:443"],
"is_ok": "0"
}]
}]
}
C# can be different. Like .Net Framework or .Net Core / .Net, so next time please provide which framework do you use.
The are two common ways to deserialize JSON string - Json.NET (3rd party) or System.Text.Json (part of .Net).
For correct deserealization first of all you must provide valid models. But sometimes JSON properties violates C# Naming Conventions or they even can't be represented in code (e.g. property name with whitespace or "is_ok" from your JSON). To avoid this you must to use property attribute that connect your property in code and property in JSON. It's:
[JsonProperty("PropertyName")] for Json.NET
[JsonPropertyName("PropertyName")] for System.Text.Json
So, summing up the above, you must add models similar to this:
public class ResultWrapper
{
[JsonProperty("result")] //use one of it based on selected library
[JsonPropertyName("result")]
public List<Result> Result { get; set; }
}
public class Result
{
[JsonProperty("company")]
[JsonPropertyName("company")]
public string Company { get; set; }
[JsonProperty("results")]
[JsonPropertyName("results")]
public List<ResultItem> Results { get; set; }
}
public class ResultItem
{
[JsonProperty("name")]
[JsonPropertyName("name")]
public string Name { get; set; }
[JsonProperty("access")]
[JsonPropertyName("access")]
public List<string> Access { get; set; }
[JsonProperty("is_ok")]
[JsonPropertyName("is_ok")]
public string IsOk { get; set; }
}
and use one of next deserealization methods:
//Json.Net
var deserializedJsonNet = JsonConvert.DeserializeObject<ResultWrapper>(jsonFromQuestion);
//System.Text.Json
var deserializedSystemTextJson = JsonSerializer.Deserialize<ResultWrapper>(jsonFromQuestion);

Cross-referencing two parts of one JSON file in C#?

Newbie question. I have a semi-complex JSON file that I have parsed in my program. The relevant parts are below:
{
"version": "36",
"released": "20220223",
"samples": {
"Samp1": [
{
"code": "A01",
"status": "Optimal",
"bestBy": "20210918",
"expires": "20211018",
"elementKeys": {
"H": [
"Hydrogen-std1-slt4"
]
}
},
{
"code": "A02",
"status": "Optimal",
"bestBy": "20211201",
"expires": "20220501",
"elementKeys": {
"H": [
"Hydrogen-std1-slt5"
]
}
},
{
"code": "A03",
"status": "Optimal",
"bestBy": "20230201",
"expires": "20230801",
"elementKeys": {
"H": [
"Hydrogen-std1-slt6"
]
}
}
],
"Samp2": [ ...
"Samp3": [ ...
"Samp4": [ ...
},
"element": {
"Hydrogen-std1-slt4": {
"format": "1.0",
"position": 4,
"standard": "std1",
...
...
}
What I need to do is populate some windows form controls with data from this file. However, thanks to the odd architecture, I'm a little frustrated over how to populate the controls for "code", "status", "bestBy", etc contained within the "samples" arrays (Samp1, 2, 3, and 4).
Only some of the samples are relevant and the relevancy is defined by whether or not the name of the element key is found further below in the JSON file. So, using the example above, within "element", the object "Hydrogen-std1-slt4" is found in the body of the JSON file with its own key-value pairs. I would like the program to see that and recognize that "Hydrogen-std1-slt4" is also found within the object in the "Samp1" array with the code "A01", the status of "Optimal", the best-by date of "20210918", and that it expires on "20211018". Since it isn't found in any other place in "Samp1", the program can ignore the other objects.
What would be the easiest, most logical way to go about making a conditional for that?
try this code
var jsonParsed = JObject.Parse(json);
string[] elementKeys = ((JObject)jsonParsed["element"]).Properties().Select(x => x.Name).ToArray();
List<Samp> data= GetData(((JObject) jsonParsed["samples"]), elementKeys);
public List<Samp> GetData(JObject samples, string[] elementKeys)
{
List<Samp> result = new List<Samp>();
foreach (var element in samples.Properties())
foreach (var item in element.Value)
if ( item["elementKeys"]["H"]!=null
&& item["elementKeys"]["H"].ToObject<string[]>()
.Any(x => elementKeys.Contains(x)) )
result.Add(item.ToObject<Samp>());
return result;
}
classes
public class Samp
{
public string code { get; set; }
public string status { get; set; }
public string bestBy { get; set; }
public string expires { get; set; }
public ElementKeys elementKeys { get; set; }
}
public class ElementKeys
{
public List<string> H { get; set; }
}

Converting Complex JSON to C# Model

I am trying to resolve the some complex JSON I am receiving to convert it to a C# Model so I can analyse and manipulate the data. I have tried converting the JSON by using JSON to C# but it doesn't work well when the name is dynamic. I want to focus on the Data.
The Item1 and SubItem1 etc are all variable strings so I can't hard code a model to pull them and the text is just a string within. The issue I am having is how to get the JSON into a usable format to access the Item1, SubItem1 and text values to manipulate their data.
I have looked into Dictionaries as suggested elsewhere but I am having no luck.
Model I have tried
public class Data
{
public string Status { get; set; }
public ResultInfo ResultInfo { get; set; }
public string Message { get; set; }
public Dictionary<string, SubData> Data {get;set;}
}
public class SubData
{
public Dictionary<string,List<string>> item {get;set;}
}
JSON
{
"Status": "OK",
"ResultInfo": {
"Prev": "PageUPURL",
"Next": "PageDownURL",
"total_count": "37",
"per_page": "3",
"page": "1"
},
"Message": "Ok.",
"Data": {
"Item1": [
{
"SubItem1": [
"Text"
]
}
],
"Item2": [
{
"SubItem2": [
"Text",
"Text",
"Text"
]
}
],
"Item3": [
{
"SubItem3": [
"Text"
]
},
{
"SubItem4": [
"Text"
]
}
]
}
}
Any suggestions, advice or help would be gratefully received.
For those task I use https://app.quicktype.io .
Because it can easly reconnize dictionary when the property name are numeric you just need to edit your Json a little.
And past it into the tool.
{
"Status": "OK",
"ResultInfo": {
"Prev": "PageUPURL",
"Next": "PageDownURL",
"total_count": "37",
"per_page": "3",
"page": "1"
},
"Message": "Ok.",
"Data": {
"1": [
{
"1": [
"Text"
]
}
],
"2": [
{
"1": [
"Text",
"Text",
"Text"
]
}
],
"3": [
{
"1": [
"Text"
]
},
{
"2": [
"Text"
]
}
]
}
}
The result class is :
public partial class Root
{
[JsonProperty("Status")]
public string Status { get; set; }
[JsonProperty("ResultInfo")]
public ResultInfo ResultInfo { get; set; }
[JsonProperty("Message")]
public string Message { get; set; }
[JsonProperty("Data")]
public Dictionary<string, List<Dictionary<string, List<string>>>> Data { get; set; }
}
public partial class ResultInfo
{
[JsonProperty("Prev")]
public string Prev { get; set; }
[JsonProperty("Next")]
public string Next { get; set; }
[JsonProperty("total_count")]
[JsonConverter(typeof(ParseStringConverter))]
public long TotalCount { get; set; }
[JsonProperty("per_page")]
[JsonConverter(typeof(ParseStringConverter))]
public long PerPage { get; set; }
[JsonProperty("page")]
[JsonConverter(typeof(ParseStringConverter))]
public long Page { get; set; }
}
Online Demo https://dotnetfiddle.net/1j42kR
nota bene: that tool also included a converter from "string" to "long" for "per_page": "3",
Change below line
public Dictionary<string, SubData> Data {get;set;}
as
public Dictionary<string, Dictionary<string, string[]>[]> Data { get; set; }

Serialize some relationships to JSON, but not all

I have the following problem: I am trying to serialize an object (object1) to Json using Newtonsoft.Json package. I need to be able to send it to a server. The problem is object1 has several referenced objects, some that should be created together with object1, but one of them is "read only" on the server, so it must be send as a relationship.
I am using string json = JsonConvert.SerializeObject
Example:
<code>
[DataContract]
public class Object1
{
// Simple Properties
[JsonProperty(PropertyName = "ext_ref", Order = 1)]
public string ExtRef { get; set; }
[JsonProperty(PropertyName = "external_comment", Order = 1)]
public string ExternalComment { get; set; }
[JsonProperty(PropertyName = "internal_comment", Order = 1)]
public string InternalComment { get; set; }
[JsonProperty(PropertyName = "object2")]
public Object2 Object2 { get; set; }
[JsonProperty(PropertyName = "object3")]
public Object3 Object3 { get; set; }
}
</code>
This is how I get it atm. This is fine for most of the objects, but not all:
{
"data": {
"attributes": {
"ext_ref": "2573421",
"external_comment": "Ext Comment",
"internal_comment": "Internal comment",
"object2": {
"data": {
"attributes": {
"xx":"XX",
"yy":"YY"
},
"id": "1",
"type": "object2s"
},
"object3": {
"data": {
"attributes": {
"xx":"XX",
"yy":"YY"
},
"id": "1",
"type": "object3s"
}
},
},
"type": "object1"
}
Because the object2 is a "special case", where it can only be understood by the server as a link, it needs to look like this:
{
"data": {
"attributes":{
"ext_ref": "2573421",
"external_comment": "Ext Comment",
"internal_comment": "Internal comment",
"object3": {
"data": {
"attributes": {
"xx":"XX",
"yy":"YY"
},
"id": "1",
"type": "object3s"
}
},
"type": "object1",
"relationships":{
"object2": {
"data": {
"id": "1",
"type": "object2s"
}
}
}
}
Now my question is this: Is there an easy way of doing this?
I have tried the following:
Using the Relationship attribute from JsonApiSerializer
Changing the JsonProperty settings for the object2.id property
Deleting the object2.id
I can't help thinking there must some attribute I can use to get the desired result, but atm. I am stuck
[EDIT]
I added an example object structure
Ok, I found the error. I am using Newtonsoft.Json to create the Json with this call:
string json = JsonConvert.SerializeObject(order, Format.None,
new JsonApiSerializerSettings {
NullValueHandling = NullValueHandling.Ignore
});
The part that caused the problem was the Format.None, which made the Json come out as basic Json, and not the usual format. I changed it to null, and I got the result I wanted. Big woop, wanna fight about it?

how to generate json string with an integer as key?

I want to generate json string like this in C# language
{
"error": "0",
"message": "messages",
"data": {
"version": "sring",
"1": [
{
"keyword": "",
"title": ""
},
{
"keyword": "",
"title": ""
}
],
"2": [
...
],
"3": [
...
]
}
}
there is a problem here, "1":[{},{}],how to generate this part? I'm using asp.net mvc project by the way, I want to return this json string to the client web browser.
This response can be simply generated using Dictionary<string, object> with arrays as values.
public class KeywordTitle
{
public string keyword { get; set; }
public string title { get; set; }
}
public class Response
{
public string error { get; set; }
public string message { get; set; }
public Dictionary<string, object> data { get; set; }
}
var dictionary = new Dictionary<string, object> {
{"version", "sring"}
};
dictionary.Add("1", new []
{
new KeywordTitle { keyword = "", title = "" },
new KeywordTitle { keyword = "", title = "" },
new KeywordTitle { keyword = "", title = "" }
});
JsonConvert.SerializeObject(new Response
{
error = "0",
message = "messages",
data = dictionary
});
It generates:
{
"error" : "0",
"message" : "messages",
"data" : {
"version" : "sring",
"1" : [{
"keyword" : "",
"title" : ""
}, {
"keyword" : "",
"title" : ""
}, {
"keyword" : "",
"title" : ""
}
]
}
}
If it is your API, then it is a good idea to extract version in order to make all objects in data be of the same type, and keys of type int.
Get the Json.NET from NuGet. Then, in your MVC model use this data annotation on your Array property
[JsonProperty(PropertyName="1")]
public string[] YourProperty { get; set }
The PropertyName value is used when you serialize data to JSON.
If you are using Newtonsoft.Json NuGet package, serializing a Dictionary<int, List<MyClass>> will get you what you the expected result.
Use Json.net and add the following attribute to the properties you what to modify the name of:
[JsonProperty(PropertyName = "1")]
public List<ObjectName> Objects { get; set; }
For more information have a look at the serialization attributes.

Categories