JSON Parsing issue with C# and RestSharp - c#

I am parsing the following JSON:
{
result: [
{
EventType: {
EventTypeDesc: "horse-racing",
events: {
Local: {
Events: {
530857: {
Venue: "Northam",
StateCode: "WA",
CountryCode: "AUS"
},
530858: {
Venue: "Caulfield",
StateCode: "VIC",
CountryCode: "AUS"
}
}
}
}
}
}
]
}
I can access the element through following code:
responseDeserializeObject.result[0].EventType.events.Local.Events["530857"].Venue
However, the following C# code doesn't work:
dynamic responseDeserializeObject = HttpGetResponse(endPoint);
foreach (var event in responseDeserializeObject.result[0].EventType.events.Local.Events)
{
Console.WriteLine(event.Venue);
Console.WriteLine(event.StateCode);
Console.WriteLine(event.CountryCode);
}
Any help will be highly appreciated.

I think your Events is a dictionary, so you need to get KeyValuePair in the foreach loop and access it's Value property. And also change the scoped variable name event, it will not compile, event is a reserved word.
dynamic responseDeserializeObject = HttpGetResponse(endPoint);
foreach (var ev in responseDeserializeObject.result[0].EventType.events.Local.Events)
{
var value = ev.Value;
Console.WriteLine(value.Venue);
Console.WriteLine(value.StateCode);
Console.WriteLine(value.CountryCode);
}

Related

Update property in json file with C#

I'm looking to change a specific property for each json record in my json file. I'd like to change the "Completed" property to "true" when a method finishes executing.
My json file looks like:
{
"LoanRecords": [
{
"LoanGUID": "{70dbec7e-5e94-460d-831c-0a5dc2d085e2}",
"RecordDT": "2020-11-10T14:44:34.378Z",
"Completed": "false",
"Environment": "TEBE",
"ProcessType": "RateLock"
},
{
"LoanGUID": "{70dbec7e-5e94-460d-831c-0a5dc2d085e2}",
"RecordDT": "2020-11-10T14:53:12.187Z",
"Completed": "false",
"Environment": "TEBE",
"ProcessType": "RateLock"
}
]
}
My C# code is the following:
private void ExecuteEvent(object sender, ElapsedEventArgs e)
{
string fileRecord = File.ReadAllText(jsonfile);
LoanRecordRoot LoanRecord = JsonConvert.DeserializeObject<LoanRecordRoot>(fileRecord);
foreach (var rec in LoanRecord.LoanRecords)
{
if (rec.Completed == "false")
{
bool recordModified = ManipulateEncompass(rec.LoanGUID, rec.ProcessType);
if (recordModified)
{
// What should I do here to update "rec.Completed" to "true"
// for this particular record and write it back to the json file
// for that specific entry?
}
}
}
Console.WriteLine("Successfully manipulated records!");
}
Is there a way to flip the "Completed" property to "true" for the specific record in my "foreach" iteration, and update the json file accordingly for that specific record? I am hoping to avoid reading the entire file, deserializing, changing the property then writing the entire content back to the json file, I'm looking to just flip that specific property for each record in my "foreach" loop. -- I hope that makes sense.
I've looked at similar questions, which seem close to what I'm looking for, but the examples I've seen don't reflect writing back to the json file specifically without overwriting the file contents -- unless this specific action isn't possible, or I'm failing to understand the entire process (highly possible.)
Ex of a solution that's close to what I'm looking for: How to update a property of a JSON object using NewtonSoft -- but doesn't seem to quite fit the bill for what I'm wanting to do.
Thank you in advance for any helpful leads!
you need to save the complete JSON when you update a property of an element of the array
static void Main(string[] args)
{
const string jsonPath = #"C:\Logs\recordRoot.json";
var loanRecordRoot = JsonConvert.DeserializeObject<LoanRecordRoot>(File.ReadAllText(jsonPath));
foreach (var record in loanRecordRoot.LoanRecords)
{
if (record.Completed == "false")
{
if (ManipulateEncompass(rec.LoanGUID, rec.ProcessType))
{
record.Completed = "true";
}
}
}
//Save Json
var json = JsonConvert.SerializeObject(loanRecordRoot, Formatting.Indented);
File.WriteAllText(jsonPath, json);
}
Looking at your JSON, it appears the "Completed" property is being serialized as of type string
Therefore, all you need to do is set it to "Completed": "true" within your condition in your snippet.
if (recordModified)
{
rec.Completed = "true";
}
At the end of your processing, simply serialize your LoanRecord object and write it back to your file.
using Kitchen_Mini_Project.Constants;
using Kitchen_Mini_Project.Moduls;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Kitchen_Mini_Project.Services
{
public class Update
{
public static void UpdateAnyProduct()
{
string readdedFile = File.ReadAllText(PathConst.ProductDBPath);
IList<Restaurant> products = JsonConvert.DeserializeObject<IList<Restaurant>>(readdedFile);
foreach (var product in products[0].FoodItems)
{
if (product.foodName == "Chicken Burrito")
{
product.foodName = "Chicken Burrito is Update ha ha";
}
}
var json = JsonConvert.SerializeObject(products, Formatting.Indented);
File.WriteAllText(PathConst.ProductDBPath, json);
}
}
}
1-install package Newtonsoft.Json
https://learn.microsoft.com/en-us/nuget/consume-packages/install-use-packages-visual-studio
2-use
string json = File.ReadAllText("server_client _input.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);
(For Install package use of this page :https://www.newtonsoft.com/json)

Newton-soft - How to add values to nested attributes which not even exists

I have below Json structure
{
"Name": "abc",
"Grade": "a"
}
Now, i want to add values to the attributes which is location in hierarchy. For example, i want to add value just like below -
Name.Lavel-1.Lavel-2.Lavel-3.Direaction = "East"
As above, i have to add value of "Direction" attribute, which itself is located inside Lavel-3 attribute which does not exists. Same way, Lavel-1 and Lavel-2 does not even exist at the time of addition.
So, my requirement is to add the required hierarchy and then add the value. So, after the addition, the json should look like below
{
"Name": "Jack",
"Grade": "A",
"Lavel-1": {
"Lavel-2": {
"Lavel-3": {
"Direction": "East"
}
}
}
}
I google and tried some solutions, but most of them are simple adding/Updating the values to an existing path,i.e, where the hierarchy is already available,and the modification is done only of the Leaf node.
Need help, if we can achieve this with efficiency.
One way is to add new JObjects and JProperties:
var jstring= #"{
""Name"": ""abc"",
""Grade"": ""a""
}";
var json = JObject.Parse(jstring);
json.Add(
new JProperty("Lavel-1",
new JObject(new JProperty("Lavel-2",
new JObject(new JProperty("Lavel-3",
new JObject(new JProperty("Direction","East"))
))
))
)
);
Thank you Magnetron for the response.
updating answer which helps me to get my needs as it can help other dev as well.
I found the below steps on another stackoverflow thread which satisfy my need. I change a little bit. Below code block will add the path ( if not exists) and set the value.
private void AddPropertyToJTokenWithValue(JToken jtoken, string tokenPath, string value)
{
if (jtoken == null || tokenPath == null)
{
return;
}
var pathParts = tokenPath.Split('.');
foreach (var pathPart in pathParts)
{
var partNode = jtoken.SelectToken(pathPart);
if (partNode == null)
{
try
{
if (pathPart != pathParts.Last())
{
((JObject)jtoken).Add(pathPart, new JObject());
partNode = jtoken.SelectToken(pathPart);
}
else
{
((JObject)jtoken).Add(pathPart, value);
partNode = jtoken.SelectToken(pathPart);
}
}
catch (Exception ex)
{
// log
return;
}
}
jtoken = partNode;
}
return;
}

Autodesk Forge Design Automation - Inventor - failedInstructions (FailedMissingOutput)

I am trying to use the WorkItems API to extract key paramaters of a part to a text file. The work item fails with FailedMissingOutput [KeyParameters.txt] which is the file my plugin creates in the working folder. Debugging locally the file is created successfully.
Log:
Addin Code is pretty simple:
public void RunWithArguments(Document doc, NameValueMap map)
{
LogTrace("Processing " + doc.FullFileName);
LogInputData(doc, map);
try
{
var DocDir = System.IO.Path.GetDirectoryName(doc.FullFileName);
var ParametersOutputFileName = System.IO.Path.Combine(DocDir, "KeyParameters.txt");
if (doc.DocumentType == DocumentTypeEnum.kPartDocumentObject)
{
using (new HeartBeat())
{
// TODO: handle the Inventor part here
PartDocument PartDoc = (PartDocument)doc;
ExtractKeyParams(PartDoc.ComponentDefinition.Parameters, ParametersOutputFileName);
}
}
else if (doc.DocumentType == DocumentTypeEnum.kAssemblyDocumentObject) // Assembly.
{
using (new HeartBeat())
{
// TODO: handle the Inventor assembly here
AssemblyDocument AssyDoc = (AssemblyDocument)doc;
ExtractKeyParams(AssyDoc.ComponentDefinition.Parameters, ParametersOutputFileName);
}
}
}
catch (Exception e)
{
LogError("Processing failed. " + e.ToString());
}
}
public void ExtractKeyParams(Parameters Params, string OutputFileName)
{
List<string> ParamList = new List<string>();
foreach (Parameter Param in Params)
{
if (Param.IsKey)
{
ParamList.Add(Param.Name);
}
}
string[] OutputParams = ParamList.ToArray();
System.IO.File.AppendAllLines(OutputFileName, OutputParams);
}
Activity Params...
private static Dictionary<string, Parameter> GetActivityParams()
{
return new Dictionary<string, Parameter>
{
{
Constants.Parameters.InventorDoc,
new Parameter
{
Verb = Verb.Get,
Description = "File to process"
}
},
{
"OutputParams",
new Parameter
{
Verb = Verb.Put,
LocalName = "KeyParameters.txt",
Description = "Key Parameters Output",
Ondemand = false,
Required = false
}
}
};
}
.....And Work Item arguments (With token and ids removed), the signed resource is a forge bucket resource generated to expire in 60 minutes so that shouldn't be the issue,
private static Dictionary<string, IArgument> GetWorkItemArgs()
{
Dictionary<string, string> Header = new Dictionary<string, string>();
Header.Add("Authorization", "Bearer <ACCESS_TOKEN>");
Dictionary<string, string> Header2 = new Dictionary<string, string>();
Header2.Add("Authorization", "Bearer <ACCESS_TOKEN>");
Header2.Add("Content-type", "application/octet-stream");
return new Dictionary<string, IArgument>
{
{
Constants.Parameters.InventorDoc,
new XrefTreeArgument
{
Url = "https://developer.api.autodesk.com/oss/v2/buckets/<BUCKET_KEY>/objects/box.ipt",
Headers = Header
}
},
{
"OutputParams",
new XrefTreeArgument
{
Verb = Verb.Put,
Url = "https://developer.api.autodesk.com/oss/v2/signedresources/<SIGNED_RESOURCE_ID>?region=US",
Headers = Header2
}
}
};
}
I cannot work out why the KeyParameters.txt file isn't being generated by my addin, but looking at the log it seems it is and maybe the problem is uploading it to the signed resource, my token has all the needed scopes.
The KeyParameters.txt file isn't generated because your Activity calls this function Run(Document doc). It is possible to see it in your log, check this line:
InventorCoreConsole.exe Information: 0 : Run called with box.ipt
Now just try to move your code to the Run(Document doc) function.
The RunWithArguments(Document doc, NameValueMap map) function is called in case that you have any arguments in the command line in your Activity.
https://forge.autodesk.com/en/docs/design-automation/v3/developers_guide/field-guide/#command-lines
From the error message it seems like your addin is either not generating the "KeyParameters.txt" file or generating it at the wrong location.
Is it possible that your code never enter any of the if statement or it end up in the catch statement without creating the txt file?
You can download the report using the reportUrl, there might be more information in there. You might also be able to add more logging in there to help you understand what is happening.

How to Parse Json to obtains values

This is the Json Format from the Imgur API using gallery search (heavily simplified, what matters is still there)
{
"data":[
{
"id":"q33FYFh",
"is_album":true,
"images":[
{
"id":"ObcYQRc",
"link":"https:\/\/i.imgur.com\/ObcYQRc.jpg",
"is_album":false
},
{
"id":"ifB0uac",
"link":"https:\/\/i.imgur.com\/ifB0uac.jpg",
"is_album":false
}
]
},
{
"id":"jYInL3c",
"is_album":true,
"images":[
{
"id":"bq2L5C4",
"link":"https:\/\/i.imgur.com\/bq2L5C4.jpg",
"is_album":false
},
{
"id":"Z0OPngk",
"link":"https:\/\/i.imgur.com\/Z0OPngk.jpg",
"is_album":false
}
]
},
{
"id":"8xxM5TO",
"link":"https:\/\/i.imgur.com\/8xxM5TO.jpg",
"is_album":false
}
],
"success":true,
"status":200
}
I need a way to get all image ID, not album ID, you can tell if an item is an album or a image by looking at the "is_album" tag
So first I tried to at least access the "id" subfield in the "images" field :
using Newtonsoft.Json;
string response = "Change this with the json file above"
dynamic dynJson = JsonConvert.DeserializeObject(response);
foreach (var data in dynJson)
{
string id = data["images"]["id"].ToString();
Debug.WriteLine(id);
}
This gave me this error : (By the way, I need to use Debug.WriteLine because Console doesn't work in PCL code in Xamarin.Forms)
System.InvalidOperationException: Cannot access child value on Newtonsoft.Json.Linq.JProperty.
But even if it worked, it would not get the id's for the images that are not part of an album.
using pseudo code this is what I would want (I think) :
for each (item in myjson)
{
if (item.is_album == "false")
{
Console.write(item.id);
}
else
{
for each (image in element)
{
Console.write(image.id);
}
}
}
You are not accessing your data correctly based on your JSON data.
data is your top level array, so your foreach would look like this:
foreach (var data in dynJson["data"])
Inside your foreach you would access your images like this:
string id = data["images"][0]["id"].ToString();
Where 0 is the index of the images array.
So combining this with another loop to get all the images for that data:
foreach (var data in dynJson["data"])
{
if (data["is_album"] == false)
{
// continue or do something
continue;
}
foreach(var image in data["images"])
{
string id = image["id"].ToString();
Debug.WriteLine(id);
}
}
You are accessing the dynamic object incorrectly. Here is the code you need:
public static List<string> GetImageIds(string jsonData)
{
List<string> imageIds = new List<string> ();
dynamic temp = JsonConvert.DeserializeObject (jsonData);
dynamic dynJson = temp.data;
foreach (dynamic data in dynJson)
{
int j = 0;
if (data.is_album == false)
{
imageIds.Add (data.id.ToString ());
}
else
{
dynamic images = data.images;
foreach (var image in images)
{
imageIds.Add (image.id.ToString ());
}
}
}
return imageIds;
}
Note: This is a simple example of how to traverse dynamic object. You will need to add validations and business logic to it as needed per your need.
Hope this helps!

How to concatenate JObects

I have a couple JObjects that are being returned from different places but that have all the same properties. I need to concatenate/merge this into one larger jObject. Is this possible and how would I go about doing it?
I want it to have all the same proerties as the individual objects. For instance.
jObject1 = { "data": [{"name": "foo","id": "1234" }]};
jObject2 = {"data": [{ "name": "foo2", "id": "5678" }]};
Resulting in something like this.
jobject3 = { "data": [{ "name": "foo", "id": "1234"}, { "name": "foo2", "id": "5678" }]};
I'm coding in C# and the only thing I have thought about doing so far is something like this which isn't valid. Not really sure how to begin and can't really anything.
jobject3 = jObject1.Concat(jObject2);
I am trying to manually loop through each object and build a new object. I think I am close but keep getting an error when adding the second item (oAlldepartment.Add) saying "Can not add property to Newtonsoft.Json.Linq.JObject. Property with the same name already exists on object.".
dynamic dynObj = JsonConvert.DeserializeObject(people);
foreach (var item in dynObj.data)
{
string id = item.id;
string name = item.name;
department = getdepartment(id);
JObject oDepartment = new JObject();
try
{
if (!String.IsNullOrEmpty(department))
oDepartment = JObject.Parse(department);
}
catch (Exception ex)
{
}
JArray departmentArray = new JArray();
if (oDepartment != null)
{
foreach (var x in oDepartment["data"].Children())
{
try
{
JObject departmentObject = new JObject();
((JObject)departmentObject).Add(new JProperty("name", x["name"]));
((JObject)departmentObject).Add(new JProperty("department", new JObject(new JProperty("name", x["department"]["name"]))));
((JObject)departmentObject).Add(new JProperty("hire_date", x["hire_date"]));
((JObject)departmentObject).Add(new JProperty("description", x["description"]));
departmentArray.Add(departmentObject);
}
catch (Exception ex)
{
}
((JObject)x).Add(new JProperty("itemtype", "post"));
}
try
{
oAlldepartment.Add(new JProperty("", new JArray(departmentArray)));
}
catch (Exception ex)
{
}
}
}
Thanks,
Rhonda
What I ended up doing was creating a class that defined the json I wanted to return and adding the json properties from each indivual object. The other benefit is my data returned by the method to the client is cleaner as I only have to worry about the properties I need instead of a huge json object with a bunch of properties that I don't need.
Rhonda

Categories

Resources