I have some JSON data, which I wish to deserialize into a C# object.
The data looks like this:
{
"version": 0,
"guid": "2166a7d5744d47009adaa29f0e549696",
"csv": "one:1,two:2,three:3",
"method": "substract"
}
The "csv" property is giving me trouble, as I want it to be deserialized to the following csv object (it's content can change, so it can have more or less comma-separated values):
public class CSV
{
public int One {get;set;}
public bool Two {get;set;}
public int Three {get;set;}
}
I already have an object for the bigger JSON:
public class MyJsonData
{
public int Version {get;set;}
public string Guid {get;set;}
public string Csv {get;set;}
public string Method {get;set;}
}
But I just can't figure out how to parse the comma-separated string to my CSV object.
I tried adding a public CSV (string s) constructor to the CSV object and changing the type from string to CSV in the MyJsonData object, hoping C# would use that constructor (I'm using System.Text.Json) but it didn't and it threw an exception.
The only thing I can come up is separating the string by commas and using reflection to fill the CSV object properties (I've defined all possible values the string can have and expect the missing ones to be empty or have the default value for the type). But I'm looking for a more elegant solution, as I am accessing the MyJsonData object everywhere in my code, so having to separately handle a CSV object seems cumbersome and a worst-practice.
Is there any way to tell JSON what method to use to convert the string to my CSV object when deserializing?
If you use Newtonsoft.Json you will need only one more string of code
using Newtonsoft.Json;
MyJsonData myJsonData = JsonConvert.DeserializeObject<MyJsonData>(json);
public class MyJsonData
{
public CSV Csv { get; set; }
//...another properties
[JsonConstructor]
public MyJsonData(string csv)
{
Csv = new JObject(csv.Split(",")
.Select(i => i.Split(":"))
.Select(r => new JProperty(r[0].ToString(), Convert.ToInt32(r[1]))))
.ToObject<CSV>();
}
}
If you use Text.Json with Net 6+, the shortest code probably is
var jDoc = JsonNode.Parse(json);
jDoc["csv"] = new JsonObject( JsonDocument.Parse(json).RootElement
.GetProperty("csv").GetString()
.Split(",")
.Select(r => r.Split(":") )
.Select(i=> KeyValuePair.Create<string, JsonNode>(i[0], Convert.ToInt32(i[1]))));
MyJsonData myJsonData = jDoc.Deserialize<MyJsonData>( new JsonSerializerOptions {PropertyNameCaseInsensitive = true});
if you want one line of code you will probably wrap this code in a custom formater ( as it is usually in the most cases when you use Text.Json)
UPDATE
if some of CSV properties are boolean, you can try this code
Csv = new JObject(csv.Split(",")
.Select(i => i.Split(":"))
.Select(r => new JProperty(r[0].ToString(),
r[1].ToLower() =="true"||r[1].ToLower() =="false"? Convert.ToBoolean( r[1]):
Convert.ToInt32(r[1]))))
.ToObject<CSV>();
Related
First of all, I wanna say: "I know there're XML/JSON/YAML formats, and I know how they works". But now I'm facing a task to make export to CSV format file.
I've read about CSV on wikipedia, searched StackOverflow on CSV topics, and didn't find answer.
As I read, this is popular format for future Excel tables display.
Okay, if I have a simple class with only ValueType properties, it's just fine.
public class MyClass
{
public int ID { get; set; }
public string Name { get; set; }
public string ToCsvString()
{
return string.Format("{0};{1}", ID, Name);
}
public static MyClass FromCsvString(string source)
{
var parts = source.Split(';');
var id = int.Parse(parts[0]);
var name = parts[1];
return new MyClass()
{
ID = id,
Name = name,
};
}
}
But what if I have a little bit more complex class. For example with List<> of other objects.
public class MyClassWithList: MyClass
{
public MyClassWithList()
{
ItemsList = new List<string>();
}
public List<string> ItemsList { get; set; }
public string ToCsvString()
{
// How to format it for future according to CSV format?
return string.Format("{0};{1}", base.ToCsvString(), ItemsList.ToString());
}
public static MyClassWithList FromCsvString(string source)
{
var parts = source.Split(';');
var id = int.Parse(parts[0]);
var name = parts[1];
// How to get it back from CSV formatted string?
var itemsList = parts[2];
return new MyClassWithList()
{
ID = id,
Name = name,
ItemsList = new List<string>()
};
}
}
How should I serialize/deserialize it to CSV?
And final question is how to do the same about when class A contains class B instances?
First off, you have to flatten your data.
If ClassA contains a ClassB, then you'll need to create a flattened POCO that has properties that access any nested properties, e.g. ClassB_PropertyA.
You can really only have 1 variable length property and it has to be the last property, then you can have any column after a point represent a single list property.
Secondly, there is no CSV Serliazation standard. There is https://www.ietf.org/rfc/rfc4180.txt but that only deals with reading text from fields. Something as simple as changing your locale can mess up a CSV library as semicolons will be switched for commas in cultures where a common represents a decimal. There are also many bugs and edge cases in Excel that cause serialization to String to be problematic. And some data is automatically converted to Dates or Times. You need to determine which program you expect to open the CSV and learn about how it handles CSV data.
Once you have a flat POCO, then a CSV is simply a header row with the name of each property followed by a row per object. There are libraries that can help you with this.
I'm quite new to JSON with C# (Using VS2017). Tried accessing each element of this object via code (e.g. Getting the strings "Obj1", "Obj2", "Obj3" and then the values of each of their members (Id and name).
I do not know in advance how many "ObjX" there will be or their names. I'm trying to load this list into some class and then convert it into a CSV (or SQL inserts).
Tried with JSON.net and JsonFx but I think my skills are just not strong enough to understand how to do this other than brute-force string manipulation functions. Can anyone help?
{
"OBJ1":{
"id":1,
"name":"Name1",
},
"OBJ2":{
"id":2,
"name":"Name2",
},
"OBJ3":{
"id":3,
"name":"Name3",
}
}
Create a class, MyClass with two properties, int Id and string Name.
public class MyClass
{
public int Id {get; set;}
public string Name {get;set;}
}
Then, depending on how you want to do it you can either deserilize it to a Dictionary or create a MyClassRoot object with three MyClass properties.
I recommend the Dictionary approach.
If you use the Dictionary approach your code will still work if more properties gets added to the JSON. If you use the MyClassRoot solution you will need to add the corresponding property to the MyClassRoot if the json updates.
Then with JSON.Net you can deserialize the object like this.
var result = JsonConvert.DeserializeObject<Dictionary<string, MyClass>>(json);
The "OBJ1", "OBJ2" and so on will then be keys in the dictionary and you can access the values like this:
var obj1 = result["OBJ1"];
var obj1Name = obj1.Name;
var obj1Id = obj1.Id;
To get all the MyClass objects to a list, simply do the following:
var list = result.ToList();
MyClassRoot approach(not recommended at all, just a POC):
public class MyClassRoot
{
public MyClass Obj1 {get;set;}
public MyClass Obj2{get;set;}
public MyClass Obj3{get;set;}
}
var result = JsonConvert.DeserializeObject<MyClassRoot>(json);
var obj1Name = result.Obj1.Name;
var obj1Id = result.Obj1.Id;
I have the following raw JSON string:
[\"Hello World!\",\"94952923696694934\",\"MyChannel\"]
I have tried the following without luck:
My custom object class:
public class MyObject
{
public string msg { get; set; }
public string id { get; set; }
public string chn { get; set; }
}
JSON string:
string str = "[\"Hello World!\",\"94952923696694934\",\"MyChannel\"]";
1st attempt at deserilization using System.Web.Script.Serialization:
JavaScriptSerializer serializer = new JavaScriptSerializer();
MyObject obj1 = serializer.Deserialize<MyObject>(str);
2nd attempt at deserilization using Newtonsoft.Json:
MyObject obj2 = JsonConvert.DeserializeObject<MyObject>(str);
Both attempts fail. Any suggestions?
You have a JSON array of strings, not an object with property names.
So the best you can do here is to deserialize the array:
IEnumerable<string> strings =
JsonConvert.DeserializeObject<IEnumerable<string>>(str);
...then use the resulting sequence strings as you see fit.
With PubNub, you can just pass in the native String, Dictionary, or Array, and we'll JSON encode it for you on the publish side, and auto JSON decode for you on the subscriber side.
It's because your 'custom object' isn't equivalent to the json representation. The json you're deserializing is just a string[] in C# (you can also use List<string> or other IEums).
So in code you're looking for;
string[] theJson = JsonConvert.DeserializeObject<string[]>(str);
MyObject would be used for the following json;
{
"msg":"Hello World!",
"id":"94952923696694934",
"chn":"MyChannel"
}
I am trying to read json from a local .json file and parse the contents using StreamReader and Json.NET. Json & my code:
contents of .json file: {"rate":50,"information":{"height":70,"ssn":43,"name":"andrew"}}
using (var sr = new StreamReader(pathToJsonFile))
{
dynamic jsonArray = JsonConvert.DeserializeObject(sr.ReadToEnd());
foreach(var item in jsonArray)
{
Console.WriteLine(item.rate);
Console.WriteLine(item.ssn);
}
}
This gives me an error on the line foreach(var item in array): Object reference not set to an instance of an object. I am guessing this is because my json is not actually an array but that is how I am trying to parse it. How can I parse this json in order to pull out fields such as rate or ssn?
NB - please do not flag this question as a duplicate of Read and parse a Json File in C#, as that is where I got my original code from.
EDIT: As has been pointed out in other answers, jsonArray is null. That explains my error but still does not answer my question. How else can I parse this json in order to extract the desired fields?
A couple things:
If you want to manually parse out the values, you should try using JObject rather than JsonConvert.DeserializeObject. The following code should work:
dynamic jsonObject = JObject.Parse("{'rate':50,'information':{'height':70,'ssn':43,'name':'andrew'}}");
Console.WriteLine(jsonObject["rate"]);
Console.WriteLine(jsonObject["information"]["ssn"]);
However, if you know how the json is structured, you should create a .net class like:
public class Person
{
public int rate {get;set;}
public Information information {get;set;}
}
public class Information
{
public int height {get;set;}
public int ssn {get;set;}
public string name {get;set;}
}
and then use:
var person = JsonConvert.DeserializeObject<Person>(thestringtodeserialize);
That way you can have a strongly typed object.
In any case, I would check for null (DeserializeObject can obviously return null):
using (var sr = new StreamReader(pathToJsonFile))
{
dynamic jsonArray = JsonConvert.DeserializeObject(sr.ReadToEnd());
if(jsonArray != null) //new check here
{
foreach(var item in jsonArray)
{
Console.WriteLine(item.rate);
Console.WriteLine(item.ssn);
}
}
I am guessing this is because my json is not actually an array
True, the returned object is dynamic, so make use of dynamic:
var json = "{\"rate\":50,\"information\":{\"height\":70,\"ssn\":43,\"name\":\"andrew\"}}";
dynamic obj = JsonConvert.DeserializeObject(json);
Console.WriteLine("rate: {0}. ssn: {1}", obj.rate, obj.information.ssn);
See live sample here: https://dotnetfiddle.net/nQYuyX
Are you sure it's an array?
If that's the format the you expect from Json, maybe you should consider defining a class.
For example:
class SomeJsonObject
{
public int rate {get;set;}
[JsonProperty("information")] //if you want to name your property something else
public InformationObject Information {get;set;}
}
class InformationObject
{
[JsonProperty("height", NullValueHandling = NullValueHandling.Ignore)] //some other things you can do with Json
public int Height {get;set;}
public int ssn {get;set;}
public string name {get;set;}
}
This way you can just deserialize it to an object:
SomeJsonObject jsonArray = JsonConvert.DeserializeObject<SomeJsonObject>(sr.ReadToEnd());
I think your question is similar to this Deserialize JSON with C# . you can use JavaScriptSerializer
I don't get a null reference (with Json.net 6.0.3) but your code has one obvious bug:
static void Main(string[] args)
{
string s = "{'rate':50,'information':{'height':70,'ssn':43,'name':'andrew'}}".Replace('\'', '\"');
var obj = JsonConvert.DeserializeObject(s);
dynamic jsonArray = obj;
foreach (var item in jsonArray)
{
Console.WriteLine(item.rate);
Console.WriteLine(item.ssn);
}
}
The bug is Console.WriteLine(item.rate) will throw.
Your 'array' jsonArray is not actually an array, it is a dictionary!
Therefore, item=the first Key-Value-pair in the dictionary, = {"rate":50}.
You can prevent the code from throwing by getting rid of your foreach loop.
i would fire up nuget and get the JSON.net package
https://www.nuget.org/packages/Newtonsoft.Json/
http://james.newtonking.com/json
it is well documented and can save you a tonne of work.
see also http://json2csharp.com/
EDIT: you are already using this
I'm really bad with C# and would like your help doing the following; I am currently passing a Json Array to my WCF webservice. I need to take the json array and insert it into a list. I have no idea to deserialize in C#. Please suggest to me what is the best way of achieving this. My code looks as follows:
public String UpdateOrderAddress(Stream userInfo)
{
try
{
StreamReader reader = new StreamReader(userInfo);
string JSONdata = reader.ReadToEnd();
if (JSONdata == null)
{
return "null";
}
return JSONdata; // Success !
}
catch (Exception e)
{
return e.ToString();
}
}
This is the data in the string that I get from the reader
[{"date":"2013-02-22 15:30:374:021","id":"1","description":"test","name":"test"},
"date":"2013-02-25 11:56:926:020","id":"2","description":"ghy","name":"fhh"},
"date":"2013-02-25 11:56:248:026","id":"3","description":"ghfm","name":"run"}]
The code you posted doesn't show how are you trying to deserialize your json string so I don't really follow what's the relevance here but in any case, this is how to deserialize JSON into a concrete C# class.
Create a class that matches the structure of your Javascript objects as so:
public class Data
{
public string Date {get;set;}
public int ID {get;set;}
public string Description {get;set;}
public string Name {get;set;}
}
Deserialize it using the JavascriptSerializer as so:
var deserializedData = new JavaScriptSerializer().Deserialize<List<Data>>(jsonString);
Note that your original JSON string is incorrectly formatted. It's missing the opening { on each element of the array. It should really be:
[{"date":"2013-02-22
15:30:374:021","id":"1","description":"test","name":"test"},
{"date":"2013-02-25
11:56:926:020","id":"2","description":"ghy","name":"fhh"},
{"date":"2013-02-25
11:56:248:026","id":"3","description":"ghfm","name":"run"}]
Now, if you attempt to deserialize the above, as so:
string json = #"[{""date"":""2013-02-22 15:30:374:021"",""id"":""1"",""description"":""test"",""name"":""test""},
{""date"":""2013-02-25 11:56:926:020"",""id"":""2"",""description"":""ghy"",""name"":""fhh""},
{""date"":""2013-02-25 11:56:248:026"",""id"":""3"",""description"":""ghfm"",""name"":""run""}]";
var deserializedData = new JavaScriptSerializer().Deserialize<List<Data>>(json);
You'll get a nice List<Data> back.
Also note that I didn't use a DateTime field for the corresponding date field in your Javascript object, the reason being that your sample dates are not valid DateTimes or at least a DateTime object cannot be created from that string representation. For instance, "15:30:374:021" makes no sense - I would imagine that 374 is the seconds field...
You need to add a reference to System.Web.Extensions to be able to use the JavascriptSerializer.
You can create a representative class with your required properties to hold the values and use the JavascriptSerializer class. Call the Deserialize<T> method specifying your type to deserialize the JSON into your code.
Links in class names for reference.
You can use Newtonsoft.Json Library. All you will need to do is:
List<YourClass> yourClassList = JsonConvert.DeserializeObject<List<YourClass>>(JSONdata);
You find more information, even samples here