Generate JSON object dynamically - c#

I have a CSV which I am parsing to convert to JSON and then finally uploading to Azure blob.
This is an example of the CSV that I am reading and parsing. Each row will have its own JSON file.
humidity_sensor, sensor1, {"temp":"22.3","batt":"3.11","ss":"28","humidity":"52.6","dp":"12.144704512672"}
humidity_sensor, sensor1, {"batt":"3.14","ss":"16","humidity":"56.9","timestamp":1556568624,"temp":"21.7","dp":"12.784662018281"}
humidity_sensor, sensor1, {"pressure":"5.14","prop2":"16","current":"56.9","temp":"21.7","dp":"12.784662018281"}
This is the model I want to serialize it to:
public class SensorModel
{
[JsonProperty("sensorId")]
public string SensorId { get; set; }
[JsonProperty("Inbound_data")]
public Inbound Inbounddata { get; set; }
[JsonProperty("ts")]
public DateTime Ts { get; set; }
}
public class Inbound
{
}
So the output is of the following format:
{
"sensorId":"sensor1",
"data_in":{
},
"ts":"2020-02-11T18:07:29Z"
}
The value in Inbound is the JSON from the CSV which is not constant and will change with each row of the CSV.
SensorModel sensorModel = new SensorModel
{
SensorId = sensorId,
Ts = utcTimestamp,
Inbounddata = new Inbound
{
}
};
But since I am not certain what is going to be in that node I can't define the properties in the Inbound class.
I tried using dynamic like this:
dynamic data = JObject.Parse(values[r, 4].ToString());
The right hand side of this expression is the value from CSV.
How can I dynamically figure out what properties are required under the inbound node. I could have simply updated the model to set the inbound property as JObject and then while creating the model assigned value to it but I need all the values of the inbound node to translate by looking up in the database.
Is there any way to achieve this?

You could declare Inbounddata as Dictionary<string,string>
public class SensorModel
{
[JsonProperty("sensorId")]
public string SensorId { get; set; }
[JsonProperty("data_in")]
public Dictionary<string,string> Inbounddata { get; set; }
[JsonProperty("ts")]
public DateTime Ts { get; set; }
}
For example,
var sensorModel = new SensorModel
{
SensorId = "2",
Ts = DateTime.Now,
Inbounddata = new Dictionary<string,string>
{
["temp"] = "22.5",
["batt"] = "3.11",
["ss"] = "22"
}
};
var result = JsonConvert.SerializeObject(sensorModel);
Output
{"sensorId":"2","data_in":{"temp":"22.5","batt":"3.11","ss":"22"},"ts":"2020-02-24T20:46:39.9728582+05:30"}

Related

Deserializing array of JSONElement back to a concrete list not working when using System.Text.Json

I have a problem when deserializing an object. The object has a property (data) that is a list of JSONElement. I'm doing:
using var doc = JsonDocument.Parse(JsonSerializer.Serialize(result));
var e = doc.RootElement.GetProperty("data");
var data = JsonSerializer.Deserialize<List<MyItem>>(e);
The serialized result variable has the following content:
{
"data":[
{
"id":245,
"number":14,
"name":"Test"
}
],
"totalCount":-1,
"groupCount":-1,
"summary":null
}
And the MyItem class is as follows:
public class MyItem
{
public int Id { get; set; }
public int Number { get; set; }
public string Name { get; set; }
}
The data variable is a list with x items. However all items are empty instances.
What am I doing wrong?
The problem is likely that your data is using lowercase property names which are not translated to the property names in your class with the default deserialization settings.
using System.Text.Json;
dynamic result = new
{
data = new dynamic[] {
new {
id = 245,
number = 14,
name = "Test"
}
},
totalCount = -1,
groupCount = -1
};
using var doc = JsonDocument.Parse(JsonSerializer.Serialize(result));
var e = doc.RootElement.GetProperty("data");
List<MyItem> data = JsonSerializer.Deserialize<List<MyItem>>(e);
Console.WriteLine($"{data.First().Id} {data.First().Number} {data.First().Name}");
The above code won't work with your MyItem class, but try this instead:
public class MyItem
{
[JsonPropertyName("id")]
public int Id { get; set; }
[JsonPropertyName("number")]
public int Number { get; set; }
[JsonPropertyName("name")]
public string Name { get; set; }
}
If it works, either use the JsonPropertyName on all your properties or else consider changing your deserialization options.
Everythig can be done in one string of code. You just need to set PropertyNameCaseInsensitive = true of JsonSerializerOptions. Better to make it in a startup file.
List<MyItem> data = JsonDocument.Parse(json).RootElement.GetProperty("data")
.Deserialize<List<MyItem>>();

Reading and Writing Nested data JSON in C#

I have looked at several solutions over the web on reading nested json files but I haven't found one suitable to my need. Maybe because I am new to JSON. Here is my issue:
I have the following JSON in a file:
{
"ConfigError" : {
"DateSent": "2022-04-28T14:03:16.6628493-07:00",
"ToolType": "WSM",
"IsSent": true
},
"FileCopyError" : {
"DateSent": "2022-06-14T14:03:16.6628493-07:00",
"ToolType": "RMT",
"IsSent": false
}
}
For this I have written two classes. One for the Inner object:
public class SummaryEmailStatus
{
public DateTime DateSent { get; set; }
public string ToolType { get; set; }
public bool IsSent { get; set; }
}
One for the Outer Objects:
public class SummaryEmailClass
{
SummaryEmailStatus Status { get; set; } = new SummaryEmailStatus();
}
I would like to be able to read the JSON in C#. I'm primarily concerned with the inner objects. They are of same class but they need to be used differently. So ideally I'd want a function that I can pass in "ConfigError" or "FileCopyError" into and it will return SummaryEmailStatus class object populated by the values in the JSON:
public static void ReadJasonFile(string jsonFileName, string objctName)
{
List<SummaryEmailClass> emailClassList = new List<SummaryEmailClass>();
dynamic jsonFile = JsonConvert.DeserializeObject(File.ReadAllText(jsonFileName));
SummaryEmailStatus sumclass = jsonFile[objctName];
}
But this gives me a run time error saying:
Cannot implicitly convert type "Newtonsoft.Json.Linq.JObject to SummaryEmailStatus
How can I successfully parse out the inner summaryemailstatus objects?
Additionally, I'd like to be able to create the JSON data within C#. The reason being, when I read the JSON, I will do some task and then will need to update the values of the JSON with the current timestamps. I'd imagine, I'd need to rewrite the file. How can I write a nested JSON like this in C#?
If JSON is not the best way to do this, I am open to alternatives
you can try
string json = File.ReadAllText(jsonFileName);
Dictionary<string,SummaryEmailStatus> summaryEmailStatus =
JsonConvert.DeserializeObject<Dictionary<string,SummaryEmailStatus>>(json);
you can use it
SummaryEmailStatus configError = summaryEmailStatus["ConfigError"];
if you want update data
summaryEmailStatus["ConfigError"].DateSent= DateTime.Now;
and serialize back
json = JsonConvert.SerializeObject(summaryEmailStatus);
or if you have only 2 main properties, create a class
public class SummaryEmailClass
{
SummaryEmailStatus ConfigError { get; set; }
SummaryEmailStatus FileCopyError{ get; set; }
}
and use it
SummaryEmailClass summaryEmailStatus =
JsonConvert.DeserializeObject<SummaryEmailStatusClass>(json);
SummaryEmailStatus configError = summaryEmailStatus.ConfigError;
Summary
You need to convert your JObject into the type you are expecting, as shown here:
SummaryEmailStatus sumclass = jsonFile[objctName].ToObject<SummaryEmailStatus>();
Details
jsonFile[objtName] is of type JObject. The reason is because JsonConvert.DeserializeObject has no idea that you intend to convert that into a list of SummaryEmailStatus.
Once you have your array of JObjects, you can convert that into a SummaryEmailStatus as shown in the following snippet:
public static void ReadJasonFile(string jsonFileName, string objctName)
{
List<SummaryEmailClass> emailClassList = new List<SummaryEmailClass>();
dynamic jsonFile = JsonConvert.DeserializeObject(File.ReadAllText(jsonFileName));
SummaryEmailStatus sumclass = jsonFile[objctName].ToObject<SummaryEmailStatus>();
}
Easy way is kept both objects in JSON, I rewrite your code and add root. For example, if you want to write Config Error and don't write File Copy Error, you can save one of them like null.
public class ConfigError
{
public DateTime DateSent { get; set; }
public string ToolType { get; set; }
public bool IsSent { get; set; }
}
public class FileCopyError
{
public DateTime DateSent { get; set; }
public string ToolType { get; set; }
public bool IsSent { get; set; }
}
public class Root
{
public ConfigError ConfigError { get; set; }
public FileCopyError FileCopyError { get; set; }
}
//in your method to get all data
var json = File.ReadAllText(jsonFileName);
var myDeserializedClass = JsonConvert.DeserializeObject<Root>(json);
Example change config and write to file
var json = #"{
""ConfigError"" : {
""DateSent"": ""2022-04-28T14:03:16.6628493-07:00"",
""ToolType"": ""WSM"",
""IsSent"": true
},
""FileCopyError"" : {
""DateSent"": ""2022-06-14T14:03:16.6628493-07:00"",
""ToolType"": ""RMT"",
""IsSent"": false
}
}";
var conf = JsonConvert.DeserializeObject<Root>(json);
conf.ConfigError.DateSent = DateTime.Now;
conf.ConfigError.ToolType = "New way";
conf.ConfigError.IsSent = false;
conf.FileCopyError = null;
var newJson = JsonConvert.SerializeObject(conf);
File.WriteAllText("your path", newJson);

C# dynamic class - how to preserved the var name from serialize output

The variable name with # prefix changed after serialize due C# naming. How to prevent this?
//assignment of object value with #Timestamp
List<dynamic> Documents = new List<dynamic>();
Documents.Add( new { Index = ""index-name-test", Type = "doc", Id = g.ToString(),
Title = "title1", #Timestamp = DateTime.UtcNow });
foreach (var doc in Documents)
{
var json = JsonConvert.SerializeObject(new { Documents= doc });
}
as in the json value, it contain
"{\"Documents\":{\"Index\":\"index-name-test*\",\"Type\":\"doc\",\"Id\":\"76134434-2ed0-48df-9034-841b386a0dbc\",\"Title\":\"title1\",\"Timestamp\":\"2019-04-14T15:50:33.596931Z\"}}"
{"Documents":{"Index":"index-name-test*","Type":"doc","Id":"76134434-2ed0-48df-9034-841b386a0dbc","Title":"title1","Timestamp":"2019-04-14T15:50:33.596931Z"}}
How to make Timestamp become #Timestamp ?
In C#, prefixing a variable name with # is just a way to allow you to use reserved words as variable names. For example, you can do this:
var #class = "foo";
If you don't use a # you will get a compiler error. As such, when you serialise your dynamic objects, the variable name is still Timestamp. The best option would be to use a concrete class to store your data. Not only can you then control the names when serialising, but you get compile time type safety and it's far quicker than using dynamic (every time you use dynamic a kitten dies!)
So I would create two classes like this:
//Root class so you don't need to serialise an anonymous type and can easily deserialise later
public class Root
{
public List<Document> Documents { get; set; }
}
public class Document
{
public string Index { get; set; }
public string Type { get; set; }
public string Id { get; set; }
public string Title { get; set; }
//This attribute controls the JSON property name
[JsonProperty("#Timestamp")]
public string Timestamp { get; set; }
}
And serialise something like this:
var root = new Documents();
root.Documents = new List<Document>
{
new Document
{
Index = ""index-name-test",
Type = "doc",
Id = g.ToString(),
Title = "title1",
Timestamp = DateTime.UtcNow
}
};
var json = JsonConvert.SerializeObject(root);

Converting .Net object to JSON missing most properties

I'm playing around with Web API 4 for the first time and preparing to hook up connection to a MongoDb. I've defined some simple objects to represent the models but when I try to return a collection of them from the GET request of my API only one property is being included in the resulting JSON object.
public class Topic : Entity
{
public string Name { get; set; }
public List<Topic> Parents { get; set; }
public List<Topic> Children { get; set; }
public List<ContentNode> ContentNodes { get; set; }
}
public class ContentNode
{
public enum ContentNodeType { VIDEO, TEXT, AUDIO };
public ContentNodeType ContentType { get; set; }
public string Url { get; set; }
public List<int> Scores { get; set; }
public List<Link> Links { get; set; }
public List<string> Comments { get; set; }
}
public string Get()
{
List<Topic> topics = new List<Topic>();
var programming = new Topic()
{
Id = "1",
Name = "Programming"
};
var inheritanceVideo = new ContentNode()
{
ContentType = ContentNode.ContentNodeType.VIDEO,
Url = "http://youtube.com",
Scores = new List<int>() {
4, 4, 5
},
Comments = new List<string>() {
"Great video about inheritance!"
}
};
var oop = new Topic()
{
Id = "2",
Name = "Object Oriented Programming",
ContentNodes = new List<ContentNode>() {
inheritanceVideo
}
};
programming.Children.Add(oop);
topics.Add(programming);
string test = JsonConvert.SerializeObject(topics);
return test;
}
I'm using the JSON.Net library to serialize the object here but I previously used the default JSON serializer and had the GET return IEnumerable<Topic>. In both cases the JSON being returned is simply:
"[{\"Id\":\"1\"}]"
A browser request for the XML works just fine. According to the documentation for JSON.Net it doesn't seem like there should be a problem serializing these classes to JSON. Any thoughts on why this isn't working? It doesn't seem like I should need to apply explicit attributes for every member.

JavaScriptDeseializer : Can not serialize array

My application is asp.net. I have to send some values back to server. For this I create a object serialize it and send it to server. At server I try to de-serialize it
Following is my code
[Serializable]
public class PassData
{
public PassData()
{
}
public List<testWh> SelectedId { get; set; }
public string SelectedControlClientId { get; set; }
public string GroupTypeId { get; set; }
public string SectionTypeId { get; set; }
}
[Serializable]
public class testWh
{
public testWh()
{
}
public string Id { get; set; }
}
JavaScriptSerializer serializer = new JavaScriptSerializer();
//this can not serialize the SelectedId and the count remains 0
PassData data = serializer.Deserialize<PassData>(jsonString);
//this serialize in an anonymous object with key value pair
var data2 = serializer.DeserializeObject(textHiddenArguments.Text);
Following is my Json Serialized String
{
"SelectedId":{"0":"ABCD","1":"JKLM"},
"SelectedControlClientId":"YTUTOOO",
"GroupTypeId":3,
"SectionTypeId":"1"
}
quotes escaped string
"{\"SelectedId\":{\"0\":\"ABCD\",\"1\":\"JKLM\"},\"SelectedControlClientId\":\"YTUTOOO\",\"GroupTypeId\":3,\"SectionTypeId\":\"1\"}"
My Problem is Selected Id is array of testWH object. But when I try to desrialize it, the SelectedId property of PassData which is list does not get serialized and count remains zero.
I tried using array instead of List, which gave an exception "no parameter less constructor..."
Could any one explain the what I am doing wrong here ?
The key problem here is that the JSON doesn't match the objects you have constructed. You can see this by writing the data you want and serializing:
var obj = new PassData
{
SelectedId = new List<testWh>
{
new testWh { Id = "ABCD"},
new testWh { Id = "JKLM"}
},
GroupTypeId = "3",
SectionTypeId = "1",
SelectedControlClientId = "YTUTOOO"
};
string jsonString = serializer.Serialize(obj);
which gives JSON like:
{"SelectedId":[{"Id":"ABCD"},{"Id":"JKLM"}],
"SelectedControlClientId":"YTUTOOO","GroupTypeId":"3","SectionTypeId":"1"}
So now you need to decide which you want to change; the JSON or the classes. The following alternative class works fine with your original JSON, for example:
public class PassData
{
public Dictionary<string,string> SelectedId { get; set; }
public string SelectedControlClientId { get; set; }
public string GroupTypeId { get; set; }
public string SectionTypeId { get; set; }
}

Categories