Format StreamWriter to Write/Append Json in Valid format - c#

Good day,
How can i save/append JSON data in to the File with StreamWriter in a valid JSON format ? Is there a way to Format StreamWriter to append/write file in valid JSON format?
Like :
`[
{ "data1": "data1" },
{ "appended data2": "appended data2" },
{ "appended data3": "appended data3" },
]`
I'm using NewtonJson to serialize JSON from an object and then save it with StreamWriter.
WritableData an_data = new WritableData
{
Titel = tbTitel.Text,
Type = tbType.Text,
Episode = tbEps.Text,
Score = tbScore.Text,
Id = tbID.Text,
TitleEng = tbTitelEng.Text,
Status = tbStatus.Text,
StartDate = tbDateStart.Text,
EndDate = tbDateEnd.Text,
Image = pbImage.ImageLocation
};
string path = SavePath + "\\AnList";
string json = JsonConvert.SerializeObject(an_data, Formatting.Indented);
TextWriter tw = new StreamWriter(path + listFile, true);
tw.WriteLine(json);
tw.Close();
And it is being save as follows :
{
"Titel": "Test1",
"Type": "Movie",
"Episode": "1",
"Score": "6.92",
"Id": "894",
"TitleEng": "Test1",
"Status": "Finished Airing",
"StartDate": "1989-07-15",
"EndDate": "1989-07-15",
"Image": "https://myanimelist.cdn-dena.com/images/anime/5/10193.jpg"
}{
"Titel": "Test2",
"Type": "TV",
"Episode": "153",
"Score": "8.16",
"Id": "223",
"TitleEng": "Test2",
"Status": "Finished Airing",
"StartDate": "1986-02-26",
"EndDate": "1989-04-12",
"Image": "https://myanimelist.cdn-dena.com/images/anime/9/21055.jpg"
}
I couldn't find a way to format it right.
Thank you for your time.

You save your data to the file by appending text to the end. From what magic there'll be [ in the beginning and ] in the end? :)
Why don't you just create an array/list of objects you want to save to the file then serialize it as a whole and save text to the file?
var list = new List<WritableData>();
list.Add(an_data1);
list.Add(an_data2);
//...
list.Add(an_dataN);
var serialized = JsonConverter.SerializeObject(list);
// write to the file with 'overwrite' option, i.e. new StreamWriter(path, false/*!!!*/)
Or another approach is appending text one-by-one like you tried to do. It'll require some tricks:
create text file as [],
then every time you want to save your object (of the same type as the other previous objects), you need to:
open file and remove the last symbol ],
append ,,
append serialized object as you do in your example,
append ]
So every time you'll have a valid json of this, looked like this:
[
{...},
{...},
...
{...}
]

You want to add more properties to your an_data? So add more properties to the class.
var an_data = new WritableData() { //btw, use camelCase in var names
Prop1 = "foo",
Prop2 = "bar"
};
Or use a dictionary:
var an_data = new WritableData() {
AppendableData = new Dictionary<string, object>()
}
an_data.AppendableData["foo"] = "bar";
an_data.AppendableData["bar"] = "foo";

Ideally the serialized class (WriteableData) should contain all fields to be (de)serialized. If it doesn't and you manually append some json data then you won't be able to deserialize that appended data. If you really need to work around this and don't know what data the Json object may contain then consider using Dictionary to store some of that unknown data. But I'd advise to strongly type your serializable json object class. Otherwise you're just inviting hard to maintain code.

Related

How to Format the nested string json property serialized json in C#

I am facing problem to serialized or format nested string JSON.
Here is the input: Data can have dynamic values
{
"Id": 33,
"Data": "{\n \"$Datatype\": \"Val1, Val2\"\n }",
"Name": "Test"
}
I want the output without any special characters like \n, , \ etc like:
{
"Id": 33,
"Data": {
"$Datatype": "Val1, Val2"
},
"Name": "Test"
}
Data property was serialized twice. To fix it try this code
var jsonParsed = JObject.Parse(json);
jsonParsed["Data"] = JObject.Parse((string) jsonParsed["Data"]);
json = jsonParsed.ToString();

Add a list in an existing JSON value

So I have below call to a method where my argument is a json string of this type
var jsonWithSearchData = await querySearchData(jsonOut);
jsonOut ->
[
{
"data": {
"_hash": null,
"kind": "ENY",
"id": "t123",
"payload": {
"r:attributes": {
"lok:934": "#0|I"
},
"r:relations": {
"lok:1445": "15318",
"lok:8538": "08562"
},
"r:searchData": "",
"r:type": [
"5085"
]
},
"type": "EQT",
"version": "d06"
}
}
]
The querySearchData() returns me two list something like this :["P123","P124","P987"] and ["Ba123","KO817","Daaa112"]
I want to add this list in my r:searchData key above. The key inside my searchData i.e. r:Porelation and ClassA and ClassB remains static. So I would like my searchData in my input Json to finally become something like this.
"r:searchData": {
"r:Porelation":{
"ClassA": ["P123","P124","P987"],
"ClassB": ["Ba123","KO817","Daaa112"]
}
},
How can I do this? What I tried:
JArray jfinObject = JArray.Parse(jobjects);
jfinObject["r:searchData"]["r:relations"]["ClassA"] = JArray.Parse(ListofCode.ToString());
And I get below error:
System.Private.CoreLib: Exception while executing function: Function1.
Newtonsoft.Json: Accessed JArray values with invalid key value:
"r:searchData". Int32 array index expected.
There are a few ways you can add a node/object/array to existing json.
One option is to use Linq-to-Json to build up the correct model.
Assuming you have the json string described in your question, the below code will add your desired json to the r:searchData node:
var arr = JArray.Parse(json); // the json string
var payloadNode = arr[0]["data"]["payload"];
// use linq-to-json to create the correct object
var objectToAdd = new JObject(
new JProperty("r:Porelation",
new JObject(
new JProperty("r:ClassA", array1),
new JProperty("r:ClassB", array2))));
payloadNode["r:searchData"] = objectToAdd;
where array1 and array2 above could come from a linq query (or just standard arrays).
// Output:
{
"data": {
"_hash": null,
"kind": "ENY",
"id": "t123",
"payload": {
"r:attributes": {
"lok:934": "#0|I"
},
"r:relations": {
"lok:1445": "15318",
"lok:8538": "08562"
},
"r:searchData": {
"r:Porelation": {
"r:ClassA": [
"P123",
"P456"
],
"r:ClassB": [
"Ba123",
"Ba456"
]
}
},
"r:type": [
"5085"
]
},
"type": "EQT",
"version": "d06"
}
}
Online demo
Another option is to create the json from an object, which could be achieved using JToken.FromObject(). However, this will only work if you have property names which are also valid for C# properties. So, this won't work for your desired property names as they contain invalid characters for C# properties, but it might help someone else:
// create JToken with required data using anonymous type
var porelation = JToken.FromObject(new
{
ClassA = new[] { "P123", "P456" }, // replace with your arrays here
ClassB = new[] { "Ba123", "Ba456" } // and here
});
// create JObject and add to original array
var newObjectToAdd = new JObject(new JProperty("r:Porelation", porelation));
payloadNode["r:searchData"] = newObjectToAdd;

How to remove parent element from json in c#

How to covert the below json
{"data":{"id":12,"name":"jeremy","email":"jeremy#test.com"}}
to
{"id":12,"name":"jeremy","email":"jeremy#test.com"}
I want to remove the "data" element from json.
With json.net it's fairly straightforward
var input = "{\"data\":{\"id\":12,\"name\":\"jeremy\",\"email\":\"jeremy#test.com\"}}";
var result = JObject.Parse(input)["data"].ToString(Formatting.None);
Console.WriteLine(result);
Note : Formatting.None is only to preserve the formatting you had in your original example
Or Text.Json
var result = JsonDocument.Parse(input).RootElement.GetProperty("data").ToString();
Output
{"id":12,"name":"jeremy","email":"jeremy#test.com"}
Additional Resources
JObject.Parse Method (String)
Load a JObject from a string that contains JSON.
JObject.Item Property (String)
Gets or sets the JToken with the specified property name.
JToken.ToString Method (Formatting,JsonConverter[])
Returns the JSON for this token using the given formatting and
converters.
Formatting Enumeration
None 0 No special formatting is applied.
Text.Json
JsonDocument.Parse Method
Provides a mechanism for examining the structural content of a JSON
value without automatically instantiating data values.
JsonDocument.RootElement Property
Gets the root element of this JSON document
JsonElement.GetProperty Method
Gets a JsonElement representing the value of a required property
identified by propertyName.
I have a follow up question on a scenario where I don't want to remove the root element.
{
"keepMe": {
"removeMe": [
{
"id": "1",
"name": "Foo",
"email": "Foo#email.com"
},
{
"id": "2",
"name": "Bar",
"email": "Bar#email.com"
}
]
}
But I wanted it to look like
{
"keepMe": {
{
"id": "1",
"name": "Foo",
"email": "Foo#email.com"
},
{
"id": "2",
"name": "Bar",
"email": "Bar#email.com"
}
}
Using below would not work. Is there another way to do this?
var result = JObject.Parse(input)["keepMe"]["removeMe"].ToString(Formatting.None);
//{
// "id": "1",
// "name": "Foo",
// "email": "Foo#email.com"
//},
//{
// "id": "2",
// "name": "Bar",
// "email": "Bar#email.com"
//}
var result = JObject.Parse(input)["removeMe"].ToString(Formatting.None); //Null Reference
Found the answer using the SelectToken and Replace keyword
var jObj = JObject.Parse(input);
jObj.SelectToken("keepMe").Replace(jObj.SelectToken("keepMe.removeMe"));
string result = jObj.ToString();

Convert Object to Array or list

i have an object that is being passed to me from a json obj, each time it is has different feilds, i am using json.net to parse it, it is parsing it correctly and it is putting it in a list of obj
the format after serialization is:
{
"language": "EN",
"code": "test",
"name": "test",
"value": "TEST",
"id": "2222222222222222"
}
the fields are dynamic it can be up to 50 not just 5
any idea on how to parse it??
If you know the items in above format. you could create an typed object. and then you can use DataContractJsonSerializer like below.
DataContractJsonSerializer obj = new DataContractJsonSerializer(typeof(List<Student>));
List<Student> result = obj.ReadObject(stream) as List<myClass>;

JSON.NET reader problem

i got some problem when i generate .json file from spring .json ,and i got this format
{ "models": [
{
"id":1,
"modelName":"dfdsf",
"created":{
"userFullname":"demo",
"time":"150301",
"date":"20110208",
"userId":"123"
},
"remark":"dsfdf",
"updated":"~unique-id~1"
},
{
"id":2,
"modelName":"test",
"created":{
"userFullname":"test",
"time":"150301",
"date":"20110210",
"userId":"124"
},
"remark":"test",
"updated":{
"userFullname":"test",
"time":"150301",
"date":"20110209",
"userId":"test"
}
}
]}
first time i used JObject Parse for convert
JObject job = JObject.Parse(fullJson);
and the other hand i used jtoken to focus "models"
JToken jDetail = job["models"];
but the problem is {[{ xxx }]} it look like jarray i don't have any idea to convert it
i ever use JArray, JsonTextReader but it doesn't work.
could suggestion some? because if i pass this ll i set some value to object.
thank you for every idea.
string fullJson = File.ReadAllText("TextFile1.txt"); // for brevity
var job = JObject.Parse(fullJson);
var models = job.Value<JArray>("models");
Console.WriteLine(models[0]);
result:
{
"id": 1,
"modelName": "dfdsf",
"created": {
"userFullname": "demo",
"time": "150301",
"date": "20110208",
"userId": "123"
},
"remark": "dsfdf",
"updated": "~unique-id~1"
}

Categories