Update property in json file with C# - 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)

Related

System.Text.Json.JsonException: The JSON value could not be converted

I'm using Ubuntu and dotnet 3.1, running vscode's c# extension.
I need to create a List from a JSON file, my controller will do some calculations with this model List that I will pass to it
So, here is my code and the error I'm getting.
First, I thought my error was because at model my attributes were char and C#, for what I saw, cannot interpret double-quotes for char, it should be single quotes. Before losing time removing it, I just changed my type declarations to strings and it's the same error.
Can someone help me?
ElevadorModel
using System.Collections.Generic;
namespace Bla
{
public class ElevadorModel
{
public int andar { get; set; }
public string elevador { get; set; }
public string turno { get; set; }
}
}
Program.cs:
class Program
{
static void Main(string[] args)
{
var path = "../input.json";
string jsonString;
ElevadorModel elevadoresModel = new ElevadorModel();
jsonString = File.ReadAllText(path); //GetType().Name = String
Console.WriteLine(jsonString); //WORKS
elevadoresModel = JsonSerializer.Deserialize<ElevadorModel>(jsonString);
}
JSON:
Your input json has an array as the base token, whereas you're expecting an object. You need to change your deserialization to an array of objects.
var elevadoresModels = JsonSerializer.Deserialize<List<ElevadorModel>>(jsonString);
elevadoresModel = elavoresModels.First();
Your input JSON is an array of models, however you're trying to deserialize it to a single model.
var models = JsonSerializer.Deserialize<List<ElevadorModel>>(jsonString);
This is also a problem in Blazor-Client side. For those calling a single object
e.g ClassName = await Http.GetFromJsonAsync<ClassName>($"api/ClassName/{id}");
This will fail to Deserialize. Using the same System.Text.Json it can be done by:
List<ClassName> ListName = await Http.GetFromJsonAsync<List<ClassName>>($"api/ClassName/{id}");
You can use an array or a list. For some reason System.Text.Json, does not give errors and it is successfully able Deserialize.
To access your object, knowing that it is a single object use:
ListName[0].Property
In your case the latter solution is fine but with the path as the input.
In my case, I was pulling the JSON data to deserialize out of an HTTP response body. It looked like this:
var resp = await _client.GetAsync($"{endpoint}");
var respBody = await resp.Content.ReadAsStringAsync();
var listOfInstances = JsonSerializer.Deserialize<List<modelType>>(respBody);
And the error would show up. Upon further investigation, I found the respBody string had the JSON base object (an array) wrapped in double quotes...something like this:
"[{\"prop\":\"value\"},...]"
So I added
respBody = respBody.Trim('\"');
And the error changed! Now it was pointing to an invalid character '\'.
I changed that line to include
respBody = respBody.Trim('\"').Replace("\\", "");
and it began to deserialize perfectly.
For reference:
var resp = await _client.GetAsync($"{endpoint}");
var respBody = await resp.Content.ReadAsStringAsync();
respBody = respBody.Trim('\"').Replace("\\", "");
var listOfInstances = JsonSerializer.Deserialize<List<modelType>>(respBody);

Adding object to JSON file

I'm creating a software on which I added a profiles feature where the user can create profile to load his informations faster. To store these informations, I'm using a JSON file, which contains as much objects as there are profiles.
Here is the format of the JSON file when a profile is contained (not the actual one, an example) :
{
"Profile-name": {
"form_email": "example#example.com",
//Many other informations...
}
}
Here is the code I'm using to write the JSON and its content :
string json = File.ReadAllText("profiles.json");
dynamic profiles = JsonConvert.DeserializeObject(json);
if (profiles == null)
{
File.WriteAllText(jsonFilePath, "{}");
json = File.ReadAllText(jsonFilePath);
profiles = JsonConvert.DeserializeObject<Dictionary<string, Profile_Name>>(json);
}
profiles.Add(profile_name.Text, new Profile_Name { form_email = form_email.Text });
var newJson = JsonConvert.SerializeObject(profiles, Formatting.Indented);
File.WriteAllText(jsonFilePath, newJson);
profile_tr.Nodes.Add(profile_name.Text, profile_name.Text);
debug_tb.Text += newJson;
But when the profiles.json file is completely empty, the profile is successfully written, but when I'm trying to ADD a profile when another one already exists, I get this error :
The best overloaded method match for 'Newtonsoft.Json.Linq.JObject.Add(string, Newtonsoft.Json.Linq.JToken)' has some invalid arguments on the profiles.Add(); line.
By the way, you can notice that I need to add {} by a non-trivial way in the file if it's empty, maybe it has something to do with the error ?
The expected output would be this JSON file :
{
"Profile-name": {
"form_email": "example#example.com",
//Many other informations...
},
"Second-profile": {
"form_email": "anotherexample#example.com"
//Some other informations...
}
}
Okay so I found by reading my code again, so I just replaced dynamic profiles = JsonConvert.DeserializeObject(json); to dynamic profiles = JsonConvert.DeserializeObject<Dictionary<string, Profile_Name>>(json);.
But it still don't fix the non-trivial way I use to add the {} to my file...
The object the first DeserializeObject method returns is actually a JObject, but below you deserialize it as a Dictionary. You shouldn't be mixing the types, choose either one.
If you use the JObject then to add objects you need to convert them to JObjects:
profiles.Add(profile_name.Text, JObject.FromObject(new Profile_Name { form_email = form_email.Text }));
In both cases, when the profile is null you just need to initialize it:
if (profiles == null)
{
profiles = new JObject(); // or new Dictionary<string, Profile_Name>();
}

C# JsonConvert.DeserializeAnonymousType failed

I am trying to deserialize the string input in Azure function app. My input is
[{"messageid":1,
"deviceid":"Android",
"temperature":20.0,
"humidity":47.0,
"eventprocessedutctime":"2017-12-01T10:35:57.8331048Z",
"result1":{"temperature":"20","humidity":"47","Scored Labels":"NO","Scored Probabilities":"0.450145334005356"}}]
I tried to run with this code.
#r "Newtonsoft.Json"
using System.Configuration;
using System.Text;
using System.Net;
using Microsoft.Azure.Devices;
using Newtonsoft.Json;
// create proxy
static Microsoft.Azure.Devices.ServiceClient client = ServiceClient.CreateFromConnectionString(ConfigurationManager.AppSettings["myIoTHub"]);
public static async Task<HttpResponseMessage> Run(string input, HttpRequestMessage req, TraceWriter log)
{
log.Info($"ASA Job: {input}");
var data = JsonConvert.DeserializeAnonymousType(input, new { deviceid = "" });
if (!string.IsNullOrEmpty(data?.deviceid))
{
string deviceId = data.deviceid;
// string deviceId = data[0].deviceid;
log.Info($"Device: {deviceId}");
// cloud-to-device message
var msg = JsonConvert.SerializeObject(new { input });
var c2dmsg = new Microsoft.Azure.Devices.Message(Encoding.ASCII.GetBytes(msg));
// send AMQP message
await client.SendAsync(deviceId, c2dmsg);
}
return req.CreateResponse(HttpStatusCode.NoContent);
}
My interest is the deviceid and Scored Labels. But for now I can't even extract one of them. Some more the Scored Labels consists of space. The result1 is the result returned by Azure machine learning so it seems like can't be renamed.
Your problem is that your root JSON container is an array, not an object:
An array is an ordered collection of values. An array begins with [ (left bracket) and ends with ] (right bracket). Values are separated by , (comma).
An object is an unordered set of name/value pairs. An object begins with { (left brace) and ends with } (right brace).
As explained in the Json.NET docs, a JSON array needs to be deserialized into a collection, such as a .Net array. Thus you can do:
var dataArray = JsonConvert.DeserializeAnonymousType(input, new [] { new { deviceid = "" } });
var data = dataArray.SingleOrDefault();
Sample fiddle.
If you find you need to extract more than just one or two properties from your JSON, you may want to create explicit type(s) into which to deserialize. To do this you could use http://json2csharp.com/ or Paste JSON as Classes.

.NET, Why must I use *Specified property to force serialization? Is there a way to not do this?

I am using xml-serialization in my project to serialize and deserialize objects based on an xml schema. I used the xsd tool to create classes to use when serializing / deserializing the objects.
When I go to serialize the object before sending, I am forced to set the *Specified property to true in order to force the serializer to serialize all propeties that are not of type string.
Is there a way to force the serialization of all properties without having to set the *Specified property to true?
The FooSpecified property is used to control whether the Foo property must be serialized. If you always want to serialize the property, just remove the FooSpecified property.
I know this is an old question, but none of the other answers (except perhaps the suggestion of using Xsd2Code) really produces an ideal solution when you're generating code as part of your build and your .xsd may change several times during a single release cycle.
An easy way for me to get what I really wanted and still use xsd.exe was to run the generated file through a simple post-processor. The code for the post-processor is as follows:
namespace XsdAutoSpecify
{
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
class Program
{
static void Main(string[] args)
{
try
{
if (args.Length != 1)
{
throw new ArgumentException("Specify a file name");
}
string fileName = args[0];
Regex regex = new Regex(".*private bool (?<fieldName>.*)Specified;");
IList<string> result = new List<string>();
IDictionary<string, string> edits = new Dictionary<string, string>();
foreach (string line in File.ReadLines(fileName))
{
result.Add(line);
if (line.Contains("public partial class"))
{
// Don't pollute other classes which may contain like-named fields
edits.Clear();
}
else if (regex.IsMatch(line))
{
// We found a "private bool fooSpecified;" line. Add
// an entry to our edit dictionary.
string fieldName = regex.Match(line).Groups["fieldName"].Value;
string lineToAppend = string.Format("this.{0} = value;", fieldName);
string newLine = string.Format(" this.{0}Specified = true;", fieldName);
edits[lineToAppend] = newLine;
}
else if (edits.ContainsKey(line.Trim()))
{
// Use our edit dictionary to add an autospecifier to the foo setter, as follows:
// set {
// this.fooField = value;
// this.fooFieldSpecified = true;
// }
result.Add(edits[line.Trim()]);
}
}
// Overwrite the result
File.WriteAllLines(fileName, result);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
Environment.Exit(-1);
}
}
}
}
The result is generated code similar to the following:
[System.Xml.Serialization.XmlAttributeAttribute()]
public barEnum foo {
get {
return this.fooField;
}
set {
this.fooField = value;
this.fooFieldSpecified = true;
}
}
You could add a default value to your schema and then use the DefaultValueAttribute.
For example, you could have the following in your schema:
<xs:element name="color" type="xs:string" default="red"/>
And then the following property for serialization:
[DefaultValue(red)]
public string color { get; set; }
This should force the color property to always serialize as "red" if it has not been explicitly set to something else.
I faced same issue and ended up setting all *Specified properties to true by reflection.
Like
var customer = new Customer();
foreach (var propertyInfo in typeof(Customer).GetProperties().Where(p => p.Name.EndsWith("Specified")))
{
propertyInfo.SetValue(customer, true);
}
We found that the answer to this question is to make sure that the schema elements are all defined as string data types. This will make sure that the serializer serializes all fields without the use of the correlated *specified property.

storing JSON data in db

I'm trying to store data from fb wall into database.
My *.cs code
public ActionResult GetWall()
{
JSONObject wallData = helper.Get("/me/feed");
if (wallData != null)
{
var data = wallData.Dictionary["data"];
List<JSONObject> wallPosts = data.Array.ToList<JSONObject>();
ViewData["Wall"] = wallPosts;
}
return View("Index");
}
Which gets posts from fb wall.
And then I have an *.aspx file, which "breaks" my wallposts into pieces (objects) or whatever you like to call them.
foreach (Facebook.JSONObject wallItem in wallPosts)
{
string wallItemType = wallItem.Dictionary["type"].String;
//AND SO ON...
What i'm trying to say is that I can access to elements inside fb JSON.
Is there a way i can access to the JSON elements inside *.cs file.
Or is there a way I can store elements inside the *.aspx file to db?
And if its possible, I would like to know how. =)
Thanks for help
Don't use the SDK. Fetch the JSON Data using HttpWebRequest and then Deserialize it using System.Runtime.Serialization.Json.DataContractJsonSerializer. You just have to Create a class with same properties returned in JSON data. See the example below
string Response = Utilities.HttpUtility.Fetch("https://graph.facebook.com/me?access_token=" + AccessToken, "GET", string.Empty);
using (System.IO.MemoryStream oStream = new System.IO.MemoryStream(System.Text.Encoding.UTF8.GetBytes(Response)))
{
oStream.Position = 0;
return (Models.FacebookUser)new System.Runtime.Serialization.Json.DataContractJsonSerializer(typeof(Models.FacebookUser)).ReadObject(oStream);
}
I'm not familiar with the facebook API and the question isn't too clear, but I assume that the string wallItemType is itself a JSON string, and you wish to parse it.
I'd use the Json.Net library to parse this.
using Newtonsoft.Json;
//your code as above
foreach (Facebook.JSONObject wallItem in wallPosts)
{
string wallItemType = wallItem.Dictionary["type"].String;
//I assume wallItemType is a JSON string {"name":"foobar"} or similar
JObject o = JObject.Parse(wallItemType);
string name = (string)o["name"]; //returns 'foobar'
//and so on
you can also use the Json.Net to deserialize to a custom type. This custom type could be mapped to a SQL database using NHibernate.
If you wish to store the entire json string in a database, then you could use a document database such as CouchDB.

Categories

Resources