How to extract those values from the JSON string - c#

I have this JSON string but are not sure how I will parse out the values that are inside:
has
has2
I do succeed to parse out the "id" correctly but are not sure how to access:
CORS
CORS2
CORS3
CORS4
I get the error:
'Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.String[]' because the type requires a JSON array (e.g. [1,2,3])
I have pasted the JSON in the pastebin:
https://pastebin.com/iWgGV9VK
The code I have:
public void getInfo()
{
String JSONstring = "{ id: 'hello', name: 'Hello',has:{ CORS: false,CORS2: true},has2:{ CORS3: false,CORS4: true}}";
String id = ""; List<String> has = new List<String>(); List<String> has2 = new List<String>();
var deserializedTicker = JsonConvert.DeserializeObject<JsonInfo>(JSONstring);
id = deserializedTicker.id;
has = deserializedTicker.has.ToList();
has2 = deserializedTicker.has.ToList();
}
public class JsonInfo
{
public String id { get; set; }
public String[] has { get; set; }
public String[] has2 { get; set; }
}
I am trying with the dynamic approach using an object but gets an error here also:
''Newtonsoft.Json.Linq.JValue' does not contain a definition for 'id''
//responseBody holds the JSON string
dynamic stuff = JsonConvert.DeserializeObject(responseBody);
foreach (var info in stuff)
{
dynamic id = info.Value.id; //''Newtonsoft.Json.Linq.JValue' does not contain a definition for 'id''
dynamic has = info.Value.has;
dynamic has2 = info.Value.has2;
if (has != null && has2 != null)
{
dynamic cors = has.CORS;
if(cors != null)
{
MessageBox.Show(cors.ToString());
}
}
}

First off, let's correct your JSON:
{
"id": "hello",
"name": "Hello",
"has": {
"CORS": false,
"CORS2": true
},
"has2": {
"CORS3": false,
"CORS4": true
}
}
Now, the problem you are experiencing is because you are attempting to deserialize the value in "has" and "has2" as arrays. In the JSON, they are not arrays; they are objects. As such, you need to define new classes with the same properties so the JSON can be properly deserialized:
public class JsonInfo
{
public string id { get; set; }
public string name { get; set; }
public JsonHasInfo has { get; set; }
public JsonHas2Info has2 { get; set; }
}
public class JsonHasInfo
{
public bool CORS { get; set; }
public bool CORS2 { get; set; }
}
public class JsonHas2Info
{
public bool CORS3 { get; set; }
public bool CORS4 { get; set; }
}
Now you should be able to deserialize the (correct) JSON properly:
String JSONstring = "{ \"id\": \"hello\", \"name\": \"Hello\", \"has\": { \"CORS\": false, \"CORS2\": true }, \"has2\": { \"CORS3\": false, \"CORS4\": true } }\";"
var deserializedTicker = JsonConvert.DeserializeObject<JsonInfo>(JSONstring);

You json was incorrect, the key has contains a dict no list.
You need change your deserialize to dictionary or change your json.
Here you can see an example:
https://json-schema.org/understanding-json-schema/reference/array.html#array

In your JSON, has is an object, not an array. You should model your class to support an object containing the attributes CORS, CORS2, and so on, and so forth.
Edit: If you want to stick to has being an array, you should change your JSON to match what an array expects, which could be like: has: [ false, true ], and omit the CORS thing.

Related

How to delete data from json File in C# [duplicate]

I have a settings.json file present in the Release folder of my application. What I want to do is change the value of it, not temporarily, permanently.. That means, deleting the old entry, writing a new one and saving it.
Here is the format of the JSON file
{
"Admins":["234567"],
"ApiKey":"Text",
"mainLog": "syslog.log",
"UseSeparateProcesses": "false",
"AutoStartAllBots": "true",
"Bots": [
{
"Username":"BOT USERNAME",
"Password":"BOT PASSWORD",
"DisplayName":"TestBot",
"Backpack":"",
"ChatResponse":"Hi there bro",
"logFile": "TestBot.log",
"BotControlClass": "Text",
"MaximumTradeTime":180,
"MaximumActionGap":30,
"DisplayNamePrefix":"[AutomatedBot] ",
"TradePollingInterval":800,
"LogLevel":"Success",
"AutoStart": "true"
}
]
}
Suppose I want to change the password value and instead of BOT PASSWORD I want it to be only password. How do I do that?
Here's a simple & cheap way to do it (assuming .NET 4.0 and up):
string json = File.ReadAllText("settings.json");
dynamic jsonObj = Newtonsoft.Json.JsonConvert.DeserializeObject(json);
jsonObj["Bots"][0]["Password"] = "new password";
string output = Newtonsoft.Json.JsonConvert.SerializeObject(jsonObj, Newtonsoft.Json.Formatting.Indented);
File.WriteAllText("settings.json", output);
The use of dynamic lets you index right into json objects and arrays very simply. However, you do lose out on compile-time checking. For quick-and-dirty it's really nice but for production code you'd probably want the fully fleshed-out classes as per #gitesh.tyagi's solution.
Use the JObject class in Newtonsoft.Json.Linq to modify JSON values without knowing the JSON structure ahead of time:
using Newtonsoft.Json.Linq;
string jsonString = File.ReadAllText("myfile.json");
// Convert the JSON string to a JObject:
JObject jObject = Newtonsoft.Json.JsonConvert.DeserializeObject(jsonString) as JObject;
// Select a nested property using a single string:
JToken jToken = jObject.SelectToken("Bots[0].Password");
// Update the value of the property:
jToken.Replace("myNewPassword123");
// Convert the JObject back to a string:
string updatedJsonString = jObject.ToString();
File.WriteAllText("myfile.json", updatedJsonString);
Example:
// This is the JSON string from the question
string jsonString = "{\"Admins\":[\"234567\"],\"ApiKey\":\"Text\",\"mainLog\":\"syslog.log\",\"UseSeparateProcesses\":\"false\",\"AutoStartAllBots\":\"true\",\"Bots\":[{\"Username\":\"BOT USERNAME\",\"Password\":\"BOT PASSWORD\",\"DisplayName\":\"TestBot\",\"Backpack\":\"\",\"ChatResponse\":\"Hi there bro\",\"logFile\":\"TestBot.log\",\"BotControlClass\":\"Text\",\"MaximumTradeTime\":180,\"MaximumActionGap\":30,\"DisplayNamePrefix\":\"[AutomatedBot] \",\"TradePollingInterval\":800,\"LogLevel\":\"Success\",\"AutoStart\":\"true\"}]}";
JObject jObject = Newtonsoft.Json.JsonConvert.DeserializeObject(jsonString) as JObject;
// Update a string value:
JToken jToken = jObject.SelectToken("Bots[0].Password");
jToken.Replace("myNewPassword123");
// Update an integer value:
JToken jToken2 = jObject.SelectToken("Bots[0].TradePollingInterval");
jToken2.Replace(555);
// Update a boolean value:
JToken jToken3 = jObject.SelectToken("Bots[0].AutoStart");
jToken3.Replace(false);
// Get an indented/formatted string:
string updatedJsonString = jObject.ToString();
//Output:
//{
// "Admins": [
// "234567"
// ],
// "ApiKey": "Text",
// "mainLog": "syslog.log",
// "UseSeparateProcesses": "false",
// "AutoStartAllBots": "true",
// "Bots": [
// {
// "Username": "BOT USERNAME",
// "Password": "password",
// "DisplayName": "TestBot",
// "Backpack": "",
// "ChatResponse": "Hi there bro",
// "logFile": "TestBot.log",
// "BotControlClass": "Text",
// "MaximumTradeTime": 180,
// "MaximumActionGap": 30,
// "DisplayNamePrefix": "[AutomatedBot] ",
// "TradePollingInterval": 555,
// "LogLevel": "Success",
// "AutoStart": false
// }
// ]
//}
You must have classes to instantiate json values to :
public class Bot
{
public string Username { get; set; }
public string Password { get; set; }
public string DisplayName { get; set; }
public string Backpack { get; set; }
public string ChatResponse { get; set; }
public string logFile { get; set; }
public string BotControlClass { get; set; }
public int MaximumTradeTime { get; set; }
public int MaximumActionGap { get; set; }
public string DisplayNamePrefix { get; set; }
public int TradePollingInterval { get; set; }
public string LogLevel { get; set; }
public string AutoStart { get; set; }
}
public class RootObject
{
public List<string> Admins { get; set; }
public string ApiKey { get; set; }
public string mainLog { get; set; }
public string UseSeparateProcesses { get; set; }
public string AutoStartAllBots { get; set; }
public List<Bot> Bots { get; set; }
}
Answer to your Ques(Untested code) :
//Read file to string
string json = File.ReadAllText("PATH TO settings.json");
//Deserialize from file to object:
var rootObject = new RootObject();
JsonConvert.PopulateObject(json, rootObject);
//Change Value
rootObject.Bots[0].Password = "password";
// serialize JSON directly to a file again
using (StreamWriter file = File.CreateText(#"PATH TO settings.json"))
{
JsonSerializer serializer = new JsonSerializer();
serializer.Serialize(file, rootObject);
}

How to pass class name to JSON DeserializeObject at runtime?

Given that I have JSON like this:
[
{
"ct_IncludeinSummary": true,
"ct_allocationid": "12345",
"allocationclassname": "group1",
"allocationname": "name1",
"opendate": "2018-12-30T05:00:00",
"closeddate": null,
"yearendvalue": 2863.93,
"qrgendvalue": 2.06,
"ct_risk": 2
},
{
"ct_IncludeinSummary": true,
"ct_allocationassetid": "5678",
"allocationclassname": "group2",
"allocationname": "name2",
"opendate": "2018-12-30T05:00:00",
"closeddate": null,
"yearendvalue": 13538223.76,
"qrgendvalue": 17337143.84,
"ct_risk": 3
},
{
"ct_IncludeinSummary": true,
"ct_allocationassetid": "89012",
"allocationclassname": "group3",
"allocationname": "name3",
"opendate": "2019-11-18T05:00:00",
"closeddate": null,
"yearendvalue": 0.0,
"qrgendvalue": 561480.62,
"ct_risk": 5
}
]
I can deserialize the results into a defined model and it works just fine.
var summaryConciseData = JsonConvert.DeserializeObject<List<SummaryConciseData>>(jsonresult);
public class Summaryconcisedata
{
public Summaryconcisedata(
bool ct_IncludeinSummary,
string ct_allocationassetid,
string allocationclassname,
string allocationname,
DateTime opendate,
DateTime? closeddate,
double? yearendvalue,
double? qrgendvalue,
int ct_risk
)
{
this.IncludeinSummary = ct_IncludeinSummary;
this.allocationid = ct_allocationassetid;
this.allocationclassname = allocationclassname;
this.allocationname = allocationname;
this.opendate = opendate;
this.closeddate = closeddate;
this.yearendvalue = yearendvalue;
this.qrgendvalue = qrgendvalue;
this.risk = risk;
}
public bool IncludeinSummary { get; }
public string allocationid { get; }
public string allocationclassname { get; }
public string allocationname { get; }
public DateTime opendate { get; }
public DateTime? closeddate { get; }
public double? yearendvalue { get; }
public double? qrgendvalue { get; }
public int risk { get; }
}
What I am trying to do is to have a large number of classes (Around 30 in all) I can deserialize and load into models
var summaryConciseData = JsonConvert.DeserializeObject(jsonresult, Type.GetType("API.HelperClass.SummaryConciseData"));
I get the following error:
Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'API.HelperClass.SummaryConciseData' because the type requires a JSON object (e.g. {"name":"value"}) to deserialize correctly.
Any idea on how I this can be a List<> ?
I've gone through most all of the similar questions to be found but none refer to any data that is in a List
MakeGenericType on list/ienumerable type should work just fine:
var listType = typeof(List<>).MakeGenericType(Type.GetType("API.HelperClass.SummaryConciseData");
var summaryConciseData = JsonConvert.DeserializeObject(jsonresult, listType);

Compare JSON array and JSON object: Cannot convert Array to String error

I am trying to compare json value and based on that i want to update the existing value,for example, currently we have "value" : [r0] in json, i want to compare and if value : [r0] ,then update it to [r0,r1] but iam hiting error that it cannot compare and there is a cast issue, could someone suggest what could be done
public void updateJsonParameter(string file)
{
try
{
var list = new List<string> { "joe", "test" };
JArray array = new JArray(list);
var jobject = JObject.Parse(file);
var ringvalue = (string)jobject["properties"]["parameters"]["ringValue"]["value"]; // unable to case here and compare
jobject["properties"]["parameters"]["ringValue"]["value"] = array; // able to update value but i want to update after comparing the existing values
var result = JsonConvert.SerializeObject(jobject);
}
following is the json format
{
"properties": {
"displayName": "jayatestdefid",
"description": "test assignment through API",
"metadata": {
"assignedBy": "xyz#gmail.com"
},
"policyDefinitionId": "/providers/Microsoft.Management/managementgroups/MGTest/providers/Microsoft.Authorization/policyDefinitions/test",
"parameters": {
"ringValue": {
"value": ["r0"]
}
},
"enforcementMode": "DoNotEnforce",
}
}
jobject.properties.parameters.ringValue.value is an array ["r0"] with one element "r0". If you want to check if it's an array with one element and that element is "r0", do exactly that:
var ringvalue = jobject["properties"]["parameters"]["ringValue"]["value"];
if(ringvalue.length == 1 && ringvalue[0] == "r0")
jobject["properties"]["parameters"]["ringValue"]["value"] = array;
You could compare the ringvalue (which is an JArray) using JArray.DeepEquals and then replace if the comparison returns true. For example,
var list = new List<string> { "joe", "test" };
JArray array = new JArray(list);
JArray valueToCompare = new JArray(new[]{"r0"});
var ringvalue = (JArray)jobject["properties"]["parameters"]["ringValue"]["value"];
if(JArray.DeepEquals(ringvalue,valueToCompare))
{
jobject["properties"]["parameters"]["ringValue"]["value"] = array;
}
First, as Klaycon said in his answer, it's worth noting that your "value" is not a single string. In json, whenever you see [ and ] then you have a collection, or an array, or a list.
When I work with json strings, I always like to be able to convert them into a strongly typed object. There is a very handy online tool I use all the time: http://json2csharp.com/
I took your json string that you provided and pasted it into that website. Here is that your object(s) look like when converted into c# classes:
public class RootObject // You can name this whatever you want
{
public Properties properties { get; set; }
}
public class Metadata
{
public string assignedBy { get; set; }
}
public class RingValue
{
public List<string> value { get; set; }
}
public class Parameters
{
public RingValue ringValue { get; set; }
}
public class Properties
{
public string displayName { get; set; }
public string description { get; set; }
public Metadata metadata { get; set; }
public string policyDefinitionId { get; set; }
public Parameters parameters { get; set; }
public string enforcementMode { get; set; }
}
Now, we can easily do the logic you need as follows:
// This is your json string, escaped and turned into a single string:
string file = "{ \"properties\": { \"displayName\": \"jayatestdefid\", \"description\": \"test assignment through API\", \"metadata\": { \"assignedBy\": \"xyz#gmail.com\" }, \"policyDefinitionId\": \"/providers/Microsoft.Management/managementgroups/MGTest/providers/Microsoft.Authorization/policyDefinitions/test\", \"parameters\": { \"ringValue\": { \"value\": [\"r0\"] } }, \"enforcementMode\": \"DoNotEnforce\", }}";
// Convert your json string into an instance of the RootObject class
RootObject jobject = JsonConvert.DeserializeObject<RootObject>(file);
// Get a list of all the "values"
List<string> values = jobject.properties.parameters.ringValue.value;
// Loop over your colleciton of "value" and do your logic
for (int i = 0; i < values.Count; ++i)
{
if (values[i] == "r0")
{
values[i] = "r0,r1";
}
}
// And finally, turn your object back into a json string
var result = JsonConvert.SerializeObject(jobject);
And this is the final result:
{
"properties":{
"displayName":"jayatestdefid",
"description":"test assignment through API",
"metadata":{
"assignedBy":"xyz#gmail.com"
},
"policyDefinitionId":"/providers/Microsoft.Management/managementgroups/MGTest/providers/Microsoft.Authorization/policyDefinitions/test",
"parameters":{
"ringValue":{
"value":[
"r0,r1"
]
}
},
"enforcementMode":"DoNotEnforce"
}
}

Deserialize JSON non-standard numeric array

I am using RestSharp to deserialize a JSON string. However, I am stuck in the non-standard structure: "000000001409026","000000001364365","869103022800595".
The numbers 000000001409026, 000000001364365, 869103022800595, are Id numbers of gps devices, so there may be one or multiple Id numbers in the JSON response. The file I get when making the query to the webservice using the RestSharp is the following:
{
"status": 200,
"data": [
{
"000000001409026": {
"Fecha": "2018-01-26",
"Kilometros": "84.17",
"Odometro": "8,292.27",
"Horas": "3.18"
}
},
{
"000000001364365": {
"Fecha": "2018-01-26",
"Kilometros": "0.00",
"Odometro": "0.00",
"Horas": "0.00"
}
},
{
"869103022800595": {
"Fecha": "2018-01-26",
"Kilometros": "0.00",
"Odometro": "0.00",
"Horas": "0.00"
}
}
]
}
The class that I am using is the following:
public class GpsOdometro
{
public string Fecha { get; set; }
public string Kilometros { get; set; }
public string Odometro { get; set; }
public string Horas { get; set; }
}
public class GpsEquipo
{
public Dictionary<string,GpsOdometro> GpsOdometro { get; set; }
}
public class RootObject
{
public string status { get; set; }
public List<GpsEquipo> data { get; set; }
}
Then I deserialize the json obtained but when I want to show it in a datagridview, the data is not shown.
IRestResponse json = client.Execute(request);
RootObject result = JsonConvert.DeserializeObject<RootObject>(json.Content);
DgOdometro.DataSource = result.data;
I need help to properly handle this json structure and get the gps data.
I appreciate your help.
DeserializeObject icreates 3 lists in data, however the dictionaries in those lists are null. You can grab the data from the json to fill them one by one
RootObject result = JsonConvert.DeserializeObject<RootObject>(json.Content);
JToken dataToken = JObject.Parse(json.Content).SelectToken("data");
int i = 0;
foreach (JProperty property in dataToken.Children().SelectMany(child => ((JObject)child).Properties()))
{
result.data[i++].GpsOdometro =
new Dictionary<string, GpsOdometro>
{
{ property.Name, JObject.Parse(o2.ToString()).SelectToken(property.Path).ToObject<GpsOdometro>() }
};
}

Deserializing array of enum values wih JSON.NET

I'm trying to use JSON.NET to deserialize a response from a third-party web service. This is the full code of my (contrived) example showing what I'm trying to do:
namespace JsonNetTests
{
public enum Parameter
{
Alpha = 1,
Bravo = 2,
Charlie = 3,
Delta = 4
}
public class ResponseElement
{
public int Id { get; set; }
public string Name { get; set; }
[JsonProperty(ItemConverterType = typeof(StringEnumConverter))]
public Parameter[] Parameters { get; set; }
}
public class ResponseBody
{
public string Locale { get; set; }
public string[] Errors { get; set; }
public ResponseElement[] ResponseElements { get; set; }
}
[TestFixture]
public class JsonNetTest
{
[Test]
public void TestEnumArray()
{
string jsonResponse = #"
{""ResponseBody"": {
""Locale"": ""en-US"",
""Errors"": [],
""ResponseElements"": [{
""Id"": 1,
""Name"": ""ABC"",
""Parameters"" : {
""Parameter"" : ""Alpha""
},
}, {
""Id"": 2,
""Name"": ""BCD"",
""Parameters"" : {
""Parameter"" : ""Bravo""
},
}
]
}}
";
JObject rootObject = JObject.Parse(jsonResponse);
JToken rootToken = rootObject.SelectToken("ResponseBody");
JsonSerializerSettings settings = new JsonSerializerSettings();
settings.MissingMemberHandling = MissingMemberHandling.Error;
ResponseBody body = JsonConvert.DeserializeObject<ResponseBody>(rootToken.ToString(), settings);
foreach (var element in body.ResponseElements)
{
Console.WriteLine(string.Format("{0}: {1}", element.Id, element.Name));
foreach (var parameter in element.Parameters)
{
Console.WriteLine(string.Format("\t{0}", parameter));
}
}
}
}
}
I get the following exception:
Newtonsoft.Json.JsonSerializationException : Cannot deserialize JSON object (i.e. {"name":"value"}) into type 'JsonNetTests.Parameter[]'.
The deserialized type should be a normal .NET type (i.e. not a primitive type like integer, not a collection type like an array or List) or a dictionary type (i.e. Dictionary).
To force JSON objects to deserialize add the JsonObjectAttribute to the type. Path 'ResponseElements[0].Parameters.Parameter', line 9, position 21.
I tried to use the ItemConverterType attribute to specify how the array should be deserialised:
[JsonProperty(ItemConverterType = typeof(StringEnumConverter))]
But this does not help either. Can someone advise?
You're trying to stuff an object into an array. ResponseElement.Parameters is an array of enums where you're json code is using an object to describe each parameter.
Your json looks like this:
// some json
"Parameters" : {
"Parameter" : "Alpha"
},
// more json
But to translate it into an array of enums it should look like this:
// some json
"Parameters" : [ "Alpha", "Bravo" ],
// more json
If you can't change the json, you can change your model as so:
public enum ParameterEnum
{
Alpha = 1,
Bravo = 2
}
public ParameterContainer
{
[JsonProperty(ItemConverterType = typeof(StringEnumConverter))]
public ParameterEnum Parameter {get;set;}
}
public class ResponseElement
{
public int Id { get; set; }
public string Name { get; set; }
public ParameterContainer[] Parameters { get; set; }
}
Effectively, you'll serialize the json into an array of ParameterContainers which will expose their values.

Categories

Resources