System.Text.Json modify data on the fly - c#

I got a json as input. I don't know exact structure of that file. I need only add object to "KnownCollection" which may be in file or not. So if there is a collection add item into it, if there is not create a collection with an item. Question is how to do that with System.Text.Json, we used it and I don't want to add dependency on Newtonsoft
{
"UnknownProperty": 1,
"KnownCollection": [{
"ItemProperty1": "1",
"ItemProperty2": 2
}],
// More unknown properties
}
var item = new {ItemProperty1 = "2", ItemProperty2 = 2};
var fileContent = File.ReadAllBytes(filePath);
using var jsonDocument = JsonDocument.Parse(fileContent);
var knownCollection = jsonDocument.RootElement.GetProperty("KnownCollection");
//How to add item to knownCollection?

You could add the item to array like below:
[HttpGet]
public string Index()
{
var fileContent = System.IO.File.ReadAllBytes("filePath");
using (MemoryStream memoryStream1 = new MemoryStream())
{
using (Utf8JsonWriter utf8JsonWriter1 = new Utf8JsonWriter(memoryStream1))
{
using (JsonDocument jsonDocument = JsonDocument.Parse(fileContent))
{
utf8JsonWriter1.WriteStartObject();
foreach (var element in jsonDocument.RootElement.EnumerateObject())
{
if (element.Name == "KnownCollection")
{
utf8JsonWriter1.WritePropertyName(element.Name);
utf8JsonWriter1.WriteStartArray();
// Staring new object
utf8JsonWriter1.WriteStartObject();
utf8JsonWriter1.WriteString("ItemProperty1", "2");
utf8JsonWriter1.WriteNumber("ItemProperty2", 2);
utf8JsonWriter1.WriteEndObject();
// Copying existing values from "KnownCollection" array
foreach (var testDataElement in element.Value.EnumerateArray())
{
testDataElement.WriteTo(utf8JsonWriter1);
}
utf8JsonWriter1.WriteEndArray();
}
else
{
element.WriteTo(utf8JsonWriter1);
}
}
utf8JsonWriter1.WriteEndObject();
}
}
var resultJson = Encoding.UTF8.GetString(memoryStream1.ToArray());
return resultJson;
}
}
Result:

Related

How to add property in existing json

I receive a JSON file like this:
{
"Name": "testeName",
"type": "unique",
"TestData": [{
"price": 2.3
}]
}
I want to add a new property ("type":"unique") to each object in TestData to be like this in the end:
{
"Name": "testeName",
"type": "unique",
"TestData": [{
"price": 2.3,
"type": "unique"
}]
}
Is there any way to do it with less code? I try this but there's a lot of code, I believe there must be a simpler way:
using (MemoryStream memoryStream1 = new MemoryStream())
{
using (Utf8JsonWriter utf8JsonWriter1 = new Utf8JsonWriter(memoryStream1))
{
using (JsonDocument jsonDocument = JsonDocument.ParseValue(ref reader))
{
utf8JsonWriter1.WriteStartObject();
foreach (var element in jsonDocument.RootElement.EnumerateObject())
{
if (element.Name == "price")
{
// Copying existing values from "TestData" object
foreach (var testDataElement in element.Value.EnumerateArray())
{
utf8JsonWriter1.WritePropertyName(element.Name);
// Staring new object
utf8JsonWriter1.WriteStartObject();
// Adding "Name" property
utf8JsonWriter1.WritePropertyName("type");
utf8JsonWriter1.WriteStringValue("unique");
//System.InvalidOperationException : 'Cannot write the start of an object or array without a property name. Current token type is 'String'.'
testDataElement.WriteTo(utf8JsonWriter1);
}
utf8JsonWriter1.WriteEndObject();
}
else
{
element.WriteTo(utf8JsonWriter1);
}
}
utf8JsonWriter1.WriteEndObject();
}
}
var resultJson = Encoding.UTF8.GetString(memoryStream1.ToArray());
}
you can try this code
using Newtonsoft.Json;
var jsonObject = JObject.Parse(json);
var testDataObj = (JObject) ((JArray)jsonObject["TestData"])[0];
testDataObj.Add("type", "unique");
json=jsonObject.ToString();
result
{
"Name": "testeName",
"type": "unique",
"TestData": [
{
"price": 2.3,
"type": "unique"
}
]
}
Can you use the Newtonsoft JSON Nuget package?
You can read JSON from a file, then use the JObject.Add method to add a property and value to the JSON object:
using (StreamReader file = File.OpenText("[insert your file path here]"))
using (JsonTextReader jtReader = new JsonTextReader(file))
{
JObject jObj = (JObject)JToken.ReadFrom(reader);
jObj.Add("type", "unique");
}
In .NET 6 and later you may use the new JsonNode editable JSON Document Object Model to load, modify and re-serialize your JSON:
// Load the file
JsonObject root;
using (var stream = File.OpenRead(inputFileName))
{
root = (JsonNode.Parse(GetJson()) ?? new JsonObject()).AsObject();
}
// Add "type" to "TestData[*]"
if (root["TestData"] is JsonArray array)
{
foreach (var obj in array.OfType<JsonObject>())
{
obj["type"] = "unique";
}
}
//Examine the resulting JSON string
var resultJson = root.ToString();
//Or write back the file directly, without using an intermediate JSON string
using (var stream = File.Create(outputFileName))
using (var writer = new Utf8JsonWriter(stream, new JsonWriterOptions { Indented = true }))
{
root.WriteTo(writer);
}
Demo fiddle here.

"Cannot access child value on Newtonsoft.Json.Linq.JValue"

My JSON File
{"data":
[
{"id":"1","user_code":"C016482","name":"CART 1","details":"[{\"Id\":15476,\"Name2\":\"AQUAFRESHIG TEETH (6+)\",\"SalesPriceVM\":250,\"DiscountPercentVM\":0,\"product_quantity\":3,\"Image_Url\":\"http:\\\/\\\/182.160.118.235:8099\\\/api\\\/ImageFile\\\/GetImage?enumEntityType=2&entityId=15476\"},{\"Id\":22514,\"Name2\":\"BABE ANTI OILY DANDRUFF SHAMPOO 250 ML\",\"SalesPriceVM\":1800,\"DiscountPercentVM\":0,\"product_quantity\":1,\"Image_Url\":\"http:\\\/\\\/182.160.118.235:8099\\\/api\\\/ImageFile\\\/GetImage?enumEntityType=2&entityId=22514\"},{\"Id\":19886,\"Name2\":\"ALOE VERA GEL\",\"SalesPriceVM\":1674,\"DiscountPercentVM\":0,\"product_quantity\":1,\"Image_Url\":\"http:\\\/\\\/182.160.118.235:8099\\\/api\\\/ImageFile\\\/GetImage?enumEntityType=2&entityId=19886\"}]","created_at":"2020-05-20 11:52:49","updated_at":"2020-05-20 11:52:49"},
{"id":"2","user_code":"C020552","name":"CART1","details":"[{\"Id\":15480,\"Name2\":\"LISTERINE MOUTHWASH ORIGINAL 500 ML\",\"SalesPriceVM\":460,\"DiscountPercentVM\":0,\"product_quantity\":1,\"Image_Url\":\"http:\\\/\\\/182.160.118.235:8099\\\/api\\\/ImageFile\\\/GetImage?enumEntityType=2&entityId=15480\"},{\"Id\":20572,\"Name2\":\"SAVLON ACTIVE HAND WASH RF 1000ML\",\"SalesPriceVM\":230,\"DiscountPercentVM\":0,\"product_quantity\":1,\"Image_Url\":\"http:\\\/\\\/182.160.118.235:8099\\\/api\\\/ImageFile\\\/GetImage?enumEntityType=2&entityId=20572\"},{\"Id\":25899,\"Name2\":\"HANDISANITTIZER 200ML SOLUTION\",\"SalesPriceVM\":100,\"DiscountPercentVM\":0,\"product_quantity\":2,\"Image_Url\":\"http:\\\/\\\/182.160.118.235:8099\\\/api\\\/ImageFile\\\/GetImage?enumEntityType=2&entityId=25899\"}]","created_at":"2020-05-21 01:43:10","updated_at":"2020-05-21 01:43:10"},
{"id":"3","user_code":"C020557","name":"PR 1","details":"[{\"Id\":13319,\"Name2\":\"EXIUM CAPS 20\",\"SalesPriceVM\":8.5,\"DiscountPercentVM\":0,\"product_quantity\":10,\"Image_Url\":\"http:\\\/\\\/182.160.118.235:8099\\\/api\\\/ImageFile\\\/GetImage?enumEntityType=2&entityId=13319\"},{\"Id\":16432,\"Name2\":\"DOMIDON 10MG TAB\",\"SalesPriceVM\":2,\"DiscountPercentVM\":0,\"product_quantity\":10,\"Image_Url\":\"http:\\\/\\\/182.160.118.235:8099\\\/api\\\/ImageFile\\\/GetImage?enumEntityType=2&entityId=16432\"},{\"Id\":19480,\"Name2\":\"ALOCAP SOFT CAP\",\"SalesPriceVM\":6,\"DiscountPercentVM\":0,\"product_quantity\":10,\"Image_Url\":\"http:\\\/\\\/182.160.118.235:8099\\\/api\\\/ImageFile\\\/GetImage?enumEntityType=2&entityId=19480\"},{\"Id\":23223,\"Name2\":\"CYNTA 100MG TAB.\",\"SalesPriceVM\":25,\"DiscountPercentVM\":0,\"product_quantity\":40,\"Image_Url\":\"http:\\\/\\\/182.160.118.235:8099\\\/api\\\/ImageFile\\\/GetImage?enumEntityType=2&entityId=23223\"},{\"Id\":2063,\"Name2\":\"MARLOX PLUS-200 ML-SUSPENSION\",\"SalesPriceVM\":110,\"DiscountPercentVM\":0,\"product_quantity\":1,\"Image_Url\":\"http:\\\/\\\/182.160.118.235:8099\\\/api\\\/ImageFile\\\/GetImage?enumEntityType=2&entityId=2063\"}]","created_at":"2020-05-21 07:30:29","updated_at":"2020-05-21 07:30:29"},
]
}
I am trying to read "details". In details, there are three objects I am trying to read Id,product_quantity of each object and insert them into the db table.
MY Code
public void PostSaveCartItemData()
{
var contents = File.ReadAllText("saved_carts.json");
dynamic jsonResponse = JsonConvert.DeserializeObject(contents);
int i = 0;
using (MainDataContext ctx = new MainDataContext())
{
List<SavedCartItem> list = new List<SavedCartItem>();
foreach (var item in jsonResponse.data)
{
var productId = item.details[i].Id;
var qty = item.details[i].product_quantity;
i++;
SavedCartItem entity = new SavedCartItem()
{
ProductId = productId,
Qty = qty ,
};
list.Add(entity);
}
ctx.SavedCartItems.AddRange(list);
ctx.SaveChanges();
}
}
Your kind help will be highly appreciated.
The details property is JSON encoded as a string, you need to further deserialise that value if you want to use it. Also, you should avoid using dynamic, there's no need. For example:
var jsonResponse = JObject.Parse(Json);
foreach (var item in jsonResponse["data"])
{
var detailsJson = item["details"];
var details = JArray.Parse(detailsJson.ToString());
foreach(var detail in details)
{
var productId = detail["Id"];
var qty = detail["product_quantity"];
Console.WriteLine(productId);
Console.WriteLine(qty);
}
}

How to replace multiple values in json file using c#?

I need to replace the Filename and Location in json file with new value if the API number exists in json or else it should add new json array with API,File and location.I have written foreach loop to do it but each time the contents are added to list the if condition takes the new api added and compares to the list so it keeps adding the same api again and again to json file.Plz help me resolve this..
List<DPIndex> items = JsonConvert.DeserializeObject<List<DPIndex>>(json);
foreach (var item in items)
{
foreach (var list in dpIndexList)
{
if (item.API == list.API)
{
item.File = list.File;
item.Location = list.Location;
}
else
{
item.API = list.API;
item.File = list.File;
item.Location = list.Location;
}
}
dpNewIndexList.Add(item);
}
string dpIdxObj = JsonConvert.SerializeObject(dpNewIndexList, Formatting.Indented);
Json file is as below:
[
{
"API": "422833682700000000",
"File": "daf420.dat.07-31-2019",
"Location": 2922
},
{
"API": "422833682700000000",
"File": "daf420.dat.07-31-2019",
"Location": 2922
}
]
Here is a code which will add the item to dpIndexList if an item with such "API" doesn't exist there, or will update the item in that list, if an item with such "API" exists:
foreach (var item in items)
{
// Check if the item with such API already exists in dpIndexList
var foundItem = dpIndexList.FirstOrDefault(dpItem => dpItem.API == item.API);
if (foundItem != null)
{
// Exists. Update the item in dpIndexList
foundItem.File = item.File;
foundItem.Location = item.Location;
}
else
{
// Doesn't exist. Adding to dpIndexList
dpIndexList.Add(item);
}
}
For testing locally I used the following dummy lists, and it worked:
var dpIndexList = new List<DPIndex>()
{
new DPIndex
{
API = "1",
File = "File_1_ORIG",
Location = 1111
},
new DPIndex
{
API = "2",
File = "File_2_ORIG",
Location = 2222
},
};
var items = new List<DPIndex>()
{
// Item, which exists in dpIndexList (should update the original)
new DPIndex
{
API = "2",
File = "File_2_UPDATE",
Location = 3333
},
// New item, which doesn't exist in dpIndexList (should be added)
new DPIndex
{
API = "3",
File = "File_3_NEW",
Location = 3333,
},
// Item, which should UPDATE the one above (should update that one)
new DPIndex
{
API = "3",
File = "File_3_UPDATED",
Location = 3333
},
};
P.S. Don't forget to add using System.Linq; to the top of the file.
After going through your code. It looks like you are getting values form
same object and changing it over and over again
Look at the example below
List<DPIndex> dpIndexList = new List<DPIndex>();
DPIndex index = new DPIndex() {
API = "API.1",
File="API1",
Location="1"
};
dpIndexList.Add(index);
index.API = "API.2";
As you can see I have added the index object in List dpIndexList
but after adding it I changed the value of API in same index object which leads to changed value in dpIndex List also.
You are doing the same thing with item here you are changing its state in each iteration. So in the end all values will become what was the final iteration of the loop
I say you create a object in each iteration and add it to list
And for updation use lambda
foreach (var item in items)
{
foreach (var list in dpIndexList)
{
DPIndex it = new DPIndex();
if (item.API == list.API)
{
it.File = list.File;
it.Location = list.Location;
dpNewIndexList.RemoveAll(x=> x.API == list.API);
}
else
{
it.API = list.API;
it.File = list.File;
it.Location = list.Location;
}
dpNewIndexList.Add(it);
}
}
I beleive this would help you

amazonS3client.SelectObjectContentAsync - downloading the large jsonline formate file - unwanted line break

I am trying to download a file content from the S3 bucket using the SelectObjectContentAsync method from AWSSDK for C#.
But there are some unwanted line break(\n) in mid of the raw data.
Data Example :
{"Id":1,"Name":"aaa"}, {"Id":2,"N
\name":"bbb"}
My Code :
var amazonS3Client = new AmazonS3Client(awsAccessKeyId, awsSecretAccessKey, region);
SelectObjectContentRequest selectObjectContentRequest = new SelectObjectContentRequest()
{
Bucket = bucketName,
Key = key,
ExpressionType = ExpressionType.SQL,
Expression = query,
InputSerialization = new InputSerialization()
{
JSON = new JSONInput()
{
JsonType = JsonType.Lines
},
CompressionType = CompressionType.Gzip
},
OutputSerialization = new OutputSerialization()
{
JSON = new JSONOutput()
{
RecordDelimiter = ","
}
}
};
using (var content = amazonS3Client.SelectObjectContentAsync(selectObjectContentRequest).Result.Payload)
{
foreach (var item in content)
{
if (item is RecordsEvent recordsEvent)
{
using (var reader = new StreamReader(recordsEvent.Payload, Encoding.UTF8))
{
using (var file = new StreamWriter(path, true))
{
file.WriteLine(reader.ReadToEnd());
}
}
}
}
}

Creating JSON from a CSV file in C#

First of all my apologies because this is going to be a "How to" question rather than a technical question. I have a CSV file as follows-
London,Dubai,4
Dubai,Mumbai,8
Dubai,Dhaka,4
Now my plan is to create a JSON object from that CSV in the following format-
[
{
"From": "London",
"To": "Dubai",
"Duration": 4
},
{
"From": "Dubai",
"To": "Mumbai",
"Duration": 8
},
{
"From": "Dubai",
"To": "Dhaka",
"Duration": 4
},
]
How do I go about and do that? Currently I can load the CSV using OpenFileDialog but no idea what else I should do to get it done? Use Model Classes? JSON.Net? Please advice me and some code samples would be appreciated!
You can add csv records to a List<T> and then serialize it with Newtonsoft.Json to get your required JSON object. See the example below:
class Program
{
static void Main(string[] args)
{
string[] csv = new[] { "London,Dubai,4", "Dubai,Mumbai,8", "Dubai,Dhaka,4" };
List<model> list = new List<model>();
foreach (var item in csv)
{
string[] fields = item.Split(',');
list.Add(new model
{
From = fields[0],
To = fields[1],
Duration = fields[2]
});
}
var json = JsonConvert.SerializeObject(list);
Console.WriteLine(json);
Console.ReadLine();
}
}
public class model
{
public string From { get; set; }
public string To { get; set; }
public string Duration { get; set; }
}
You can use TextFieldParser from the Microsoft.VisualBasic.FileIO namespace and Microsoft.VisualBasic.dll assembly to parse CSV files. Despite the VisualBasic name the class is perfectly usable in c#.
First, add the following extension method:
public static class TextFieldParserExtensions
{
public static IEnumerable<string []> ReadAllFields(this TextFieldParser parser)
{
if (parser == null)
throw new ArgumentNullException();
while (!parser.EndOfData)
yield return parser.ReadFields();
}
}
Now you can use LINQ to transform each CSV line into an anonymous or named type for serialization, like so:
var csv = #"London,Dubai,4
Dubai,Mumbai,8
Dubai,Dhaka,4";
string json;
using (var stream = new StringReader(csv))
using (TextFieldParser parser = new TextFieldParser(stream))
{
parser.SetDelimiters(new string[] { "," });
var query = parser.ReadAllFields()
.Select(a => new { From = a[0], To = a[1], Duration = int.Parse(a[2]) });
json = new JavaScriptSerializer().Serialize(query);
}
Here I am using JavaScriptSerializer but the same code can be used with json.net
json = JsonConvert.SerializeObject(query, Formatting.Indented);
Be sure to evaluate the query before closing the TextFieldParser.
I Believe this should work for all different kinds of .csv files
Comments are in the code
public class Program
{
public static void Main(string[] args)
{
var list = new List<Dictionary<string, string>>();
Console.WriteLine("Put in the path to your .csv file");
var response1 = Console.ReadLine();
Console.WriteLine("Initializing...");
// Read All of the lines in the .csv file
var csvFile = File.ReadAllLines(response1);
// Get The First Row and Make Those You Field Names
var fieldNamesArray = csvFile.First().Split(',');
// Get The Amount Of Columns In The .csv
// Do the -1 so you can use it for the indexer below
var fieldNamesIndex = fieldNamesArray.Count() - 1;
// Skip The First Row And Create An IEnumerable Without The Field Names
var csvValues = csvFile.Skip(1);
// Iterate Through All Of The Records
foreach (var item in csvValues)
{
var newDiction = new Dictionary<string, string>();
for (int i = 0; i < fieldNamesIndex;)
{
foreach (var field in item.Split(','))
{
// Think Of It Like This
// Each Record Is Technically A List Of Dictionary<string, string>
// Because When You Split(',') you have a string[]
// Then you iterate through that string[]
// So there is your value but now you need the field name to show up
// That is where the Index will come into play demonstrated below
// The Index starting at 0 is why I did the -1 on the fieldNamesIndex variable above
// Because technically if you count the fields below its actually 6 elements
//
// 0,1,2,3,4,5 These Are The Field Names
// 0,1,2,3,4,5 These Are The Values
// 0,1,2,3,4,5
//
// So what this is doing is int i is starting at 0 for each record
// As long as i is less than fieldNamesIndex
// Then split the record so you have all of the values
// i is used to find the fieldName in the fieldNamesArray
// Add that to the Dictionary
// Then i is incremented by 1
// Add that Dictionary to the list once all of the values have been added to the dictionary
//
// Add the field name at the specified index and the field value
newDiction.Add(fieldNamesArray.ElementAt(i++), field);
}
list.Add(newDiction);
}
}
Console.WriteLine("Would You Like To Convert To Json Now?");
Console.WriteLine("[y] or [n]");
var response = Console.ReadLine();
if (response == "y")
{
Console.WriteLine("Where Do You Want The New File?");
var response2 = Console.ReadLine();
// Serialize the list into your Json
var json = JsonConvert.SerializeObject(list);
File.Create(response2).Dispose();
File.AppendAllText(response2, json);
Console.WriteLine(json);
Console.ReadLine();
}
else
{
Console.WriteLine("Ok See You Later");
Console.ReadLine();
}
}
}

Categories

Resources