C#: Appending Json Object to a Json file already containing data - c#

I have created an object which contains data I want to insert/append to the data currently sitting in a json file.
I have succeeded in getting to to write the data to the file however it overwrites all the data that was there originally.
What i am trying to do is append this Property to the json file whilst keeping all the original information.
This is what I have done so far:
string widthBox = Width.Text.ToString();
string heightBox = Height.Text.ToString();
string WindowSizejson = File.ReadAllText(DownloadConfigFilelocation);
dynamic WindowSizejsonObj = Newtonsoft.Json.JsonConvert.DeserializeObject(WindowSizejson);
JObject windowContent = new JObject(
new JProperty("externalSite",
new JObject(
new JProperty("webLogin",
new JObject(
new JProperty("window", "height=" + heightBox + ",width=" + widthBox + ",resizable,scrollbars")
)
)
)
)
);
This is the data currently in the json file that i need to append the above to.
( have blurred out values due to company security reasons)

You have two choices that I can think of:
1.Read the entire file into an object, add your object, and then
rewrite the entire file (poor performance)
var filePath = #"path.json";
// Read existing json data
var jsonData = System.IO.File.ReadAllText(filePath);
// De-serialize to object or create new list
var SomeObjectList= JsonConvert.DeserializeObject<List<T>>(jsonData)
?? new List<T>();
// Add any new
SomeObjectList.Add(new T()
{
Name = "..."
});
SomeObjectList.Add(new T()
{
Name = "..."
});
// edit
var first = SomeObjectList.FirstOrDefault();
first.Name = "...";
// Update json data string
jsonData = JsonConvert.SerializeObject(SomeObjectList);
System.IO.File.WriteAllText(filePath, jsonData);
Open the file read/write,
parse through until you get to the closing curly brace, then write
the remaining data, then write the close curly brace (not trivial)

Instead of messing around with JProperty, deserialize your json and append your desired data:
JObject obj = JObject.Parse(jsontext);
obj["new_prop"] = "value";//new property as per hirarchy ,same for replacing values
string newjson=obj.ToString();
it's much cleaner and easier to maintain.

Related

Adding a line of Json to a Json file

I am writing a script to make configuration of a client automated. I want to be able to read a json file, and add a line in the existing json.
I have got as far as to read the json file - however I need some help with the editing of the json file
var pathToJson = Path.Combine(#"C:\" + DownloadConfigFilelocation);
var r = new StreamReader(pathToJson);
var myJson = r.ReadToEnd();
I need to add the line
"pageTitle": "Base Client",
to the json file below
I need to add this under "name".
The simplest option is to treat it as JSON: add a property, not a line:
// Load the content of the file as a string
string json = File.ReadAllText(pathToJson);
// Parse the JSON to a Newtonsoft.Json.Linq.JObject
JObject obj = JObject.Parse(json);
// Add the property
obj["pageTitle"] = "Base Client";
// Convert back to a JSON string
string newJson = obj.ToString();
// Save the string back to the file
File.WriteAllText(pathToJson, newJson);
This requires the Newtonsoft.Json NuGet package (aka Json.NET).

Adding a properties to JSON that is missing

So I have been working on JSON files over the past few days, just to understand how C# can manipulate JSON.
I need some help with adding a property to a JSON file. I have figured out how to edit values through trial and error, however, I had assumed that it would create the path where I access the value. Turns out this isn't the case.
This is what I currently have done with regards to access a values Height and Width, however, there is no "externalSite""Weblogin""window" path within the JSON
string widthBox = Width.Text.ToString();
string heightBox = Height.Text.ToString();
string CustomSizejson = File.ReadAllText(DownloadConfigFilelocation);
JObject CustomSizeobj = JObject.Parse(CustomSizejson);
CustomSizeobj["externalSite"]["webLogin"]["window"] = "height=" + heightBox + ",width=" + widthBox + ",resizable,scrollbars";
string CustomSizenewJson = CustomSizeobj.ToString();
File.WriteAllText(DownloadConfigFilelocation, CustomSizenewJson);
This is pretty much what I want to accomplish and append it to the JSON file
Can someone help me figure this out?
Thanks
You can add property using JObject.Add function. Example:
JObject json = new JObject();
json.Add("property_name", "property_value");
If you want to add something not exactly object but inside some property of it.
You first need to find property itself and use JObject.Add function. Example:
JObject inner_json = (JObject) json["property_name"];
inner_json.Add("inner_property_name","value");
You can try something like:
var input = new JObject();
input.Add("window", "height=300,width=410,resizable,scrollbars");
var obj = new JObject();
obj.Add("webLogin", input);
var obj1 = new JObject();
obj1.Add("externalSite", obj);
For more information:
JObject nested property

JSON Deserialize Error: The given key was not present in the dictionary

I'm trying to output JSON to a drop down list in a web form. I've managed to get this far:
WebClient client = new WebClient();
string getString = client.DownloadString("http://myfeed.com/app_feed.php");
JavaScriptSerializer serializer = new JavaScriptSerializer();
dynamic item = serializer.Deserialize<object>(getString);
string name = item["title"];
return name;
This brings back the feed ok but it runs into an error on the line:
string name = item["title"];
Bringing back this error:
Additional information: The given key was not present in the dictionary.
This is a sample of my feed:
{"apps":[{"title":"title1","description":"description1"},
{"title":"title2","description":"description2"},
{"title":"title3","description":"description3"}
So I thought that I was referencing the first title and I was planning to loop through them:
string name = item["title"];
But obviously not!
I have looked on Stackoverflow but I can't find an answer that I can apply to my own code.
title is inside another key apps and its an array so you should iterate it, I show you just select first one using index 0
string name = item["apps"][0]["title"];
you can access all by foreach
foreach (var ap in item["apps"])
{
Console.WriteLine(ap["title"]);
}
First, your JSON is invalid. Second: you need to loop over your items, as it is an array. If you want to access the first one, you could do: item["apps"][0]["title"]
Looping through all items:
var str = #"{""apps"":[{""title"":""title1"",""description"":""description1""},
{""title"":""title2"",""description"":""description2""},
{""title"":""title3"",""description"":""description3""}]}";
var serializer = new JavaScriptSerializer();
dynamic obj = serializer.Deserialize<object>(str);
foreach (var item in obj["apps"])
{
Console.WriteLine("item title: " + item["title"]);
}

Newtonsoft Object serialized to String. JObject instance expected

Hi so am trying to parse this JSON line but i got some others that are like this in files thats why i want to automate this so i can remove the invalid lines to make the file a valid JSON for reading, The problem is that the JSON contains multiple JSON in 1 line
Example:
{"item":"value"}{"anotheritem":"value"}
Is there anyway to remove
{"anotheritem":"value"}
So it turns in to a valid JSON that is readable to start parsing the files
I tried doing using StreamReader cause there in a file i have multiple files that contain these invalid JSON
So i got it to be able to detect the Invalid JSON but for some reason i can't get it to read the JSON so i can use .remove to remove the invalid line
using (StreamReader r = new StreamReader(itemDir))
{
string json = r.ReadToEnd();
if (json.Contains("anotheritem"))
{
JObject NoGood = JObject.FromObject(json);
MessageBox.Show(NoGood.ToString());
}
}
The Error:
Object serialized to String. JObject instance expected.
Thank you all for your time and help.
If each object are side by side without space or any other character, you can convert your string to an json array.
string value = "{\"item\":\"value\"}{\"anotheritem\":\"value\"}";
string arrayValue = "[" + value.Replace("}{", "},{") + "]";
var array = JArray.Parse(arrayValue);
var goopArray = array.OfType<JObject>().Where(o => o.Property("anotheritem") == null);
Edit : see my second answer. More robust solution. More modern. And support dotnet core builtin json serializer.
Json.Net
Even better solution, Json.NET have a builtin feature for this exact scenario. See Read Multiple Fragments With JsonReader
The JsonTextReader have a property SupportMultipleContent that allow to read consecutive items when set to true
string value = "{\"item\":\"value\"}{\"anotheritem\":\"value\"}";
var reader = new JsonTextReader(new System.IO.StringReader(value));
reader.SupportMultipleContent = true;
var list = new List<JObject>();
while (reader.Read())
{
var item = JObject.Load(reader);
list.Add(item);
}
System.Text.Json
If you want to use System.Text.Json, it's also acheivable. They are no SupportMultipleContent property but Utf8JsonReader will do the job for you.
string value = "{\"item\":\"value\"}{\"anotheritem\":\"value\"}";
var bytes = Encoding.UTF8.GetBytes(value).AsSpan();
var list = new List<JsonDocument>();
while (bytes.Length != 0)
{
var reader = new Utf8JsonReader(bytes);
var item = JsonDocument.ParseValue(ref reader);
list.Add(item);
bytes = bytes.Slice((int) reader.BytesConsumed);
}

Parsing large json

I'm trying to parse a json file and then operate on it to insert data into a SQL Server 2008 Database.
Example:
var sr = new StreamReader("C:\\path to file\file.json");
var json = JsonSerializer.SerializeToString(sr);
var o = JsonObject.Parse(json);
But I always get this error at the second line - "Timeouts are not supported on this stream."
The Json file looks like this:
"main":{
"prg": [
{
"Id": 1,
"name": "A&E",
more fields
}
"prg": [
{
"Id": 2,
"name": "asda",
more fields
}
}
I need to make something like this
foreach (prg in main)
entity.id = prg.id
entity.name = prg.name
How can I do this and why I get that timeout exception?
EDIT: To better understand my question this is how I do for an XML file
XmlDocument sourceDoc = new XmlDocument();
sourceDoc.Load(SourcesElement2); // where SourcesElement2 is the path to my XML
XmlNodeList prg = sourceDoc.GetElementsByTagName("prg");
foreach (XmlNode item in prg)
{
entity.Name= item.SelectSingleNode("name").InnerText;
...
}
I have converted the XML to Json and I want to do same thing. For every "prg" node in the Json File insert a new item in the database
EDIT2:
This is what I've done.
using (
StreamReader stream =
File.OpenText(
"C:\\path\\Sources.json")
)
{
JObject sources = (JObject) JToken.ReadFrom(new JsonTextReader(stream));
var a = sources["on"];
var b = a["sources"];
var c = b["prgs"];
foreach (var item in c)
{
var d= item.SelectToken("prg");
// Here d is null
}
I have the same question as the one from above. For every "prg" node in the Json File insert a new item in the database. How can I do this ? ( path to prg is on/sources/prgs/ )
I don't think you want to serialize the stream.
JsonSerializer.SerializeToString(sr)
You want to deserialize from the stream.
JsonSerializer.Deserialize
You might want to use JsonReader for performance reasons.
Your XML example load the whole file in the memory - you don't want to do that for large documents. reader.Read() pattern is better suited for processing large files.
For everyone with the same problem here is what I've done ( NOTE: this is just an example )
By the way, thank you for everyone who tried to answer my question and I'm sorry for my mistakes.
List<string> d = new List<string>();
using (
StreamReader stream =
File.OpenText(
"C:\\path\\Sources.json")
)
{
JObject sources = (JObject) JToken.ReadFrom(new JsonTextReader(stream));
var a = sources["on"];
var b = a["sources"];
var c = b["prgs"];
foreach (JObject item in c["prg"].ToList())
{
d.Add(item.Value<string>("name"));
}
}
//part below is just for testing
foreach (var VARIABLE in d)
{
Console.WriteLine(VARIABLE);
}
Console.ReadLine();
I would approach it by converting that JSON object into a C# class and then applying logic to the C# object and/or use DataTables
[Note: There are solutions online that show you would to easily pass an Object or List<Object> into a DataTable and then pass it "easily" to SQL]
The first step is still your hiccup in either solution, how do I pull in a large JSON string from filesystem?
if you have the JSON, use json2csharp.com and/or jsonutils.com to retrieve the classes in order to Deserialize it to your object.
StreamReader re = new StreamReader(#"C:\path to file\file.json");
JsonTextReader reader = new JsonTextReader(re);
YourClass DeserializedObject = se.Deserialize<YourClass>(reader);
Console.WriteLine(DeserializeObject.SomeProperty);

Categories