Json camel casing properties - c#

https://dotnetfiddle.net/R96sPn
I am trying to create AddJsonObject such that the name of External.AddParameter obeys whatever the ContractRevolver is set for External.Serialize
In the example below it is camel casing, but as you can see the output is not camel cased. Changing the ContractResolver should effectively determine the formatting of the name parameter. No additional code can be added to External class
This is a class that I cannot modify:
public static class External
{
public static string Serialize(object obj)
{
JsonSerializer ser = new JsonSerializer{
ContractResolver = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver(),
NullValueHandling = NullValueHandling.Ignore
};
using (StringWriter stringWriter = new StringWriter())
{
using (JsonTextWriter jsonTextWriter = new JsonTextWriter((TextWriter)stringWriter))
{
jsonTextWriter.Formatting = Formatting.Indented;
jsonTextWriter.QuoteChar = '"';
ser.Serialize((JsonWriter)jsonTextWriter, obj);
return stringWriter.ToString();
}
}
}
public static void AddParameter(string name, string str)
{
Console.WriteLine(name + " : " + str);
}
}
Just example class:
public class Product { public Product ChildProduct { get; set; } public string Name { get; set; } public DateTime Expiry { get; set; } public string[] Sizes { get; set; } }
Main:
public class Program
{
public void AddJsonObject(object obj)
{
foreach (var property in obj.GetType().GetProperties())
{
var propValue = property.GetValue(obj, null);
External.AddParameter(property.Name, External.Serialize(propValue));
}
}
public void Main()
{
Product product = new Product();
product.Name = "Apple";
product.Expiry = new DateTime(2008, 12, 28);
product.Sizes = new string[]{"small", "big"};
product.ChildProduct = new Product();
AddJsonObject(product);
}
}
Output:
ChildProduct : {
"expiry": "0001-01-01T00:00:00"
}
Name : "Apple"
Expiry : "2008-12-28T00:00:00"
Sizes : [
"small",
"big"
]
Desired Output:
childProduct : {
"expiry": "0001-01-01T00:00:00"
}
name : "Apple"
expiry : "2008-12-28T00:00:00"
sizes : [
"small",
"big"
]
This demo showcases Serialize using JSON.net with CamelCase, but AddJsonObject should work independent of what json serializer they use or what formatting. This example just showcases a non-trivial example.
My initial attempt consisted of wrapping the object into a parent object. External.Serialize() the wrapper object then somehow feed the results into AddParameter such that the name is the output of the serialization -- Couldn't get this to work right.

Change Line where you initialize ContractResolver (ContractResolver = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver()) to
ContractResolver = new DefaultContractResolver
{
NamingStrategy = new CamelCaseNamingStrategy()
};

Ok I have a solution that works, but Ill hold off anymore clever answers come up
public void AddJsonObject(object obj)
{
var jsonObj = JObject.Parse(External.Serialize(obj));
foreach (var property in jsonObj.Properties())
{
External.AddParameter(property.Name, External.Serialize( property.Value));
}
}

Related

Newtonsoft JsonConvert.SerializeObject use property name insted of [JsonProperty("")] [duplicate]

This question already has answers here:
How to ignore JsonProperty(PropertyName = "someName") when serializing json?
(2 answers)
Closed 2 years ago.
I have a class in my project which needs to be serialized for two different use cases.
As I can't add two diffrent attributes to on property I would like to serialize the objects of the class
one time with the [JsonProperty("attributname")] decleration and one time with the property name it self.
For ex:
public class Contact
{
[JsonProperty("name")]
public string Lastname { get; set; }
}
public class Program
{
public void SerializeByJsonPropertyName()
{
var contact = new Contact()
{
Lastname = "Harber"
}
var requestJson = JsonConvert.SerializeObject(contact);
// Serialized Object requestJson:
// {
// "name" = "Harber"
// }
}
public void SerializeByPropertyName()
{
var contact = new Contact()
{
Lastname = "Harber"
}
var requestJson = JsonConvert.SerializeObject(contact /*, ? Setting ?*/);
// Serialized Object requestJson:
// {
// "Lastname" = "Harber"
// }
}
}
The first szenario works totaly fine, but for the second szenario I couldĀ“t find any solution. Except creating two classes or duplicate the properties in my class.. IS there any setting in Newtonsofts JsonConverter for doing this?
Thanks for your help!
You can create different naming strategies, then create different settings, each setting has a Contract resolver, each contract resolver has a naming strategy, then you supply for each settings the naming strategy you want to use,
something like this
public static class JsonSerializingSettings {
public static JsonSerializerSettings JsonUnModified{ get; set; } = new JsonSerializerSettings
{
ContractResolver = new DefaultContractResolver() {
NamingStrategy = new UnmodifiedNamingStrategy()
}
};
public static JsonSerializerSettings JsonDefault { get; set; } = new JsonSerializerSettings
{
ContractResolver = new DefaultContractResolver() {
NamingStrategy = new DefaultNamingStrategy()
}
};
}
public class UnmodifiedNamingStrategy : NamingStrategy {
protected override string ResolvePropertyName(string name) {
return name;
}
}
and when you want to use it
var requestJson = JsonConvert.SerializeObject(contact,JsonSerializingSettings.JsonDefault);
// Serialized Object requestJson:
// {
// "name" = "Harber"
// }
var requestJson = JsonConvert.SerializeObject(contact,JsonSerializingSettings.JsonUnModified);
// Serialized Object requestJson:
// {
// "Lastname" = "Harber"
// }

How to deserialize JSON using Newtonsoft Deserialize C#

I am trying to deserialize JSON file and want to assign to object ScanResult. var text showing all the values but scanresult showing null some null values. https://gyazo.com/ff2ce386f845394c458a88d43a1f30d8
please suggest if I am missing something.
//MY jSon File SCAN Test 1-1543045410222.json 's code
{
"at": 1543045410222,
"i": 1000,
"s": {
"Sensor1": ["OFF"],
"Sensor2": ["OFF"],
"DataReady1": ["OFF"],
"DataReady2": ["OFF"],
"CV1": [5.0],
"CV2": [6.0]
}
}
//ViewModel Code is as below:
public void ResendScanResult()
{
var ScanActivities = scanActivityManager.GetAll();
foreach (var item in ScanActivities)
{
var scanName = item.ScanName;
var dir = _dataFilePath + scanName + "\\";
var jsonFileName = string.Format("{0}{1}-{2}.json", dir, scanName, item.ScanDateEpoch);
string fileName = Path.GetFileName(jsonFileName);
// ScanResult scanResult = new ScanResult();
var text = File.ReadAllText(jsonFileName);
//var scanResults = JsonConvert.DeserializeObject<ScanResult>(text);
Common.Model.ScanResult scanResult = JsonConvert.DeserializeObject<Common.Model.ScanResult>(text);
var Mvm = MonitorViewModel.Instance;
// TargetProvider target = Mvm.GetTargetProvider(scanResult);
// Mvm.PublishToServer(target, scanResult);
}
}
and my scanRescult class code is as below :
namespace ABX.Common.Model
{
public class ScanResult
{
public ScanResult()
{
At = DateTimeOffset.Now.ToUnixTimeMilliseconds();
Interval = 1;
}
public string Name { get; set; }
public long At { get; set; }
public long Interval { get; set; }
public JObject Values { get; set; }
public string FileName { get; set; }
public JObject ToJson()
{
JObject json = new JObject
{
{ "at", At },
{ "i", Interval },
{ "s", Values }
};
return json;
}
Either rename your class properties to match your JSON, rename your JSON to match your class properties, or implement a custom JsonConverter, where you can implement arbitrary mapping.

How do deserialize JSON with non-standard (and varying) property names (in .NET)

I have to read a JSON stream (which I have no control over), which is in the form:
{"files":
{
"/some_file_path.ext": {"size":"1000", "data":"xxx", "data2":"yyy"},
"/other_file_path.ext": {"size":"2000", "data":"xxx", "data2":"yyy"},
"/another_file_path.ext": {"size":"3000", "data":"xxx", "data2":"yyy"},
}
}
So, I have an object named files, which has a number of properties, which have 1) different names every time, 2) different number of them every time, and 3) names with characters which can't be used in C# properties.
How do I deserialize this?
I'm putting this into a Portable Library, so I can't use the JavaScriptSerializer, in System.Web.Script.Serialization, and I'm not sure about JSON.NET. I was hoping to use the standard DataContractJsonSerializer.
UPDATE: I've changed the sample data to be closer to the actual data, and corrected the JSON syntax in the area the wasn't important. (Still simplified quite a bit, but the other parts are fairly standard)
You can model your "files" object as a Dictionary keyed by the JSON property name:
public class RootObject
{
public Dictionary<string, PathData> files { get; set; }
}
public class PathData
{
public int size { get; set; }
public string data { get; set; }
public string data2 { get; set; }
}
Then, only if you are using .Net 4.5 or later, you can deserialize using DataContractJsonSerializer, but you must first set DataContractJsonSerializerSettings.UseSimpleDictionaryFormat = true:
var settings = new DataContractJsonSerializerSettings { UseSimpleDictionaryFormat = true };
var root = DataContractJsonSerializerHelper.GetObject<RootObject>(jsonString, settings);
With the helper method:
public static class DataContractJsonSerializerHelper
{
public static T GetObject<T>(string json, DataContractJsonSerializer serializer = null)
{
using (var stream = GenerateStreamFromString(json))
{
var obj = (serializer ?? new DataContractJsonSerializer(typeof(T))).ReadObject(stream);
return (T)obj;
}
}
public static T GetObject<T>(string json, DataContractJsonSerializerSettings settings)
{
return GetObject<T>(json, new DataContractJsonSerializer(typeof(T), settings));
}
private static MemoryStream GenerateStreamFromString(string value)
{
return new MemoryStream(Encoding.Unicode.GetBytes(value ?? ""));
}
}
Alternatively, you can install Json.NET and do:
var root = JsonConvert.DeserializeObject<RootObject>(jsonString);
Json.NET automatically serializes dictionaries to JSON objects without needing to change settings.
We need to first convert this Invalid JSON to a Valid JSON. So a Valid JSON should look like this
{
"files":
{
"FilePath" : "C:\\some\\file\\path",
"FileData" : {
"size": 1000,
"data": "xxx",
"data2": "yyy"
},
"FilePath" :"C:\\other\\file\\path",
"FileData" : {
"size": 2000,
"data": "xxx",
"data2": "yyy"
},
"FilePath" :"C:\\another\\file\\path",
"FileData" : {
"size": 3000,
"data": "xxx",
"data2": "yyy"
}
}
}
To make it a valid JSON we might use some string functions to make it looks like above. Such as
MyJSON = MyJSON.Replace("\\", "\\\\");
MyJSON = MyJSON.Replace("files", "\"files\"");
MyJSON = MyJSON.Replace("data:", "\"data:\"");
MyJSON = MyJSON.Replace("data2", "\"data2\"");
MyJSON = MyJSON.Replace(": {size", ",\"FileData\" : {\"size\"");
MyJSON = MyJSON.Replace("C:", "\"FilePath\" :\"C:");
Than we can create a class like below to read the
public class FileData
{
public int size { get; set; }
public string data { get; set; }
public string data2 { get; set; }
}
public class Files
{
public string FilePath { get; set; }
public FileData FileData { get; set; }
}
public class RootObject
{
public Files files { get; set; }
}
Assuming you have a valid JSON you could use JavaScriptSerializer to return a list of objects
string json = "{}"
var serializer = new JavaScriptSerializer();
var deserializedValues = (Dictionary<string, object>)serializer.Deserialize(json, typeof(object));
Alternatively you could specify Dictionary<string, List<string>> as the type argument
strign json = "{}";
JavaScriptSerializer serializer = new JavaScriptSerializer();
var deserializedValues = serializer.Deserialize<Dictionary<string, List<string>>>(json);
foreach (KeyValuePair<string, List<string>> kvp in deserializedValues)
{
Console.WriteLine(kvp.Key + ": " + string.Join(",", kvp.Value));
}

Convert DataSet with multiple Datatables to Json

I want to convert a dataset which has multiple data-tables within it.
Following is the example,
The dataset X has two data tables A and B
I want the result as follows,
{
"type":"A",
"value":"100",
"details":[
{"name":"John", "age":"45", "gender":"M"},
{"name":"Sebastin", "age":"34", "gender":"M"},
{"name":"Marc", "age":"23", "gender":"M"},
{"name":"Natalia", "age":"34", "gender":"F"}
]
}
Currently I am using Newtonsoft.Json. Is it possible with Newtonsoft.Json?
If not, is it possible with any other .net Json tools?
You can get the JSON you want by implementing a custom JsonConverter for the DataSet like this:
class CustomDataSetConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return (objectType == typeof(DataSet));
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
DataSet x = (DataSet)value;
JObject jObject = new JObject();
DataTable a = x.Tables["A"];
foreach (DataColumn col in a.Columns)
{
jObject.Add(col.Caption.ToLower(), a.Rows[0][col].ToString());
}
JArray jArray = new JArray();
DataTable b = x.Tables["B"];
foreach (DataRow row in b.Rows)
{
JObject jo = new JObject();
foreach (DataColumn col in b.Columns)
{
jo.Add(col.Caption.ToLower(), row[col].ToString());
}
jArray.Add(jo);
}
jObject.Add("details", jArray);
jObject.WriteTo(writer);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
Here is a demo:
class Program
{
static void Main(string[] args)
{
DataSet x = new DataSet();
DataTable a = x.Tables.Add("A");
a.Columns.Add("Type");
a.Columns.Add("Value");
a.Rows.Add("A", "100");
DataTable b = x.Tables.Add("B");
b.Columns.Add("Name");
b.Columns.Add("Age");
b.Columns.Add("Gender");
b.Rows.Add("John", "45", "M");
b.Rows.Add("Sebastian", "34", "M");
b.Rows.Add("Marc", "23", "M");
b.Rows.Add("Natalia", "34", "F");
JsonSerializerSettings settings = new JsonSerializerSettings();
settings.Converters.Add(new CustomDataSetConverter());
settings.Formatting = Formatting.Indented;
string json = JsonConvert.SerializeObject(x, settings);
Console.WriteLine(json);
}
}
Output:
{
"type": "A",
"value": "100",
"details": [
{
"name": "John",
"age": "45",
"gender": "M"
},
{
"name": "Sebastian",
"age": "34",
"gender": "M"
},
{
"name": "Marc",
"age": "23",
"gender": "M"
},
{
"name": "Natalia",
"age": "34",
"gender": "F"
}
]
}
I don't think Json.Net will do this automatically, but you should be able to do this using Typed Datasets.
A typed dataset is the same as the regular DataSet/DataTable classes, but they extend them with properties for each column in the tables and with relations.
Edit:
Alternatively you could build a method that converts the DataTable structures into a class model and then use Json.Net to serialize that. The data model would be simple, with only two classes, and the conversion should also be quite simple to implement.
Edit 2:
An example of how to convert the data table into a class structure:
public class ClassA
{
public string Type { get; set; }
public int Value { get; set; }
public List<ClassB> Details { get; set; }
public static ClassA FromDataRow(DataRow row, IEnumerable<DataRow> relatedRows)
{
var classA = new ClassA
{
Type = (string) row["Type"],
Value = (int) row["Value"],
Details = relatedRows.Select(r => new ClassB
{
Name = (string)r["Name"],
Age = (int)r["Age"],
Gender = (string)r["Gender"]
}).ToList()
};
return classA;
}
}
public class ClassB
{
public string Name { get; set; }
public int Age { get; set; }
public string Gender { get; set; }
}
Here you can run ClassA.FromDataRow() and pass it one row from TableA and a list of rows from TableB and end up with an object structure. This can easily be serialized to the format you want.
Please note that the code must be modified for your use and will probably not compile as it is. But the concept should be clear.
Final Solution for reference
using System.Web.Script.Serialization;
public class ClassA
{
public string Type { get; set; }
public string Value { get; set; }
public List<ClassB> Details { get; set; }
protected void Page_Load(object sender, EventArgs e)
{
DataSet x = new DataSet();
DataTable a = x.Tables.Add("A");
a.Columns.Add("Type");
a.Columns.Add("Value");
a.Rows.Add("A", "100");
DataTable b = x.Tables.Add("B");
b.Columns.Add("Name");
b.Columns.Add("Age");
b.Columns.Add("Gender");
b.Rows.Add("John", "45", "M");
b.Rows.Add("Sebastian", "34", "M");
b.Rows.Add("Marc", "23", "M");
b.Rows.Add("Natalia", "34", "F");
var s = FromDataRow(a.Rows[0], b.AsEnumerable());
JavaScriptSerializer jss = new JavaScriptSerializer();
string output = jss.Serialize(s);
}
public static ClassA FromDataRow(DataRow row, IEnumerable<DataRow> relatedRows)
{
var classA = new ClassA
{
Type = (string)row["Type"],
Value = (string)row["Value"],
Details = relatedRows.Select(r => new ClassB
{
Name = (string)r["Name"],
Age = (string)r["Age"],
Gender = (string)r["Gender"]
}).ToList()
};
return classA;
}
}
public class ClassB
{
public string Name { get; set; }
public string Age { get; set; }
public string Gender { get; set; }
}
Here's a simplified answer:
var datasetList= new List();
var yourChanges= yourDataset.GetChanges();
datasetList.Add(yourChanges);
Once changes are added:
JsonConert.Serialize(datasetList, Formatting.Indented);
this will generated the json for all records.

Serialization Fail on list of lists using DataContractSerializer

I have some class that has a property of type List<object> I need to serialize that class to XML file using DataContractSerializer.
The serialization fails on ArgumentException when the object is a List<T>/IEnumerator<T>exception message:
Invalid name character in
'System.Collections.Generic.List`1[[MyProj.Result, MyProj,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]'.
Here is the code sample that fails
The Class that takes the List<object>
[DataContract(IsReference = true)]
public class RecoveryMethodData
{
[DataMember]
public List<object> Parameters { get; set; }
public RecoveryMethodData()
{
Parameters = new List<object>();
}
public static void SerializeToFile(RecoveryMethodData recoveryMethodData, string fileName)
{
var encoding = Encoding.UTF8;
using (var fileWriter = new XmlTextWriter(fileName, encoding))
{
fileWriter.Formatting = Formatting.Indented;
// use SharedTypeResolver for deserializing assistance.
var serializer = new DataContractSerializer(typeof(RecoveryMethodData), null, int.MaxValue, false, true, null, new SharedTypeResolver());
serializer.WriteObject(fileWriter, recoveryMethodData);
}
}
}
Here is the usage:
private void TestSerialization()
{
var methodData = new RecoveryMethodData();
var result = new Result() {Message = "wow", Pass = true, FileName = "somefile "};
methodData.Parameters.Add(result);
methodData.Parameters.Add(true);
var list1 = new List<Result>();
list1.Add(new Result(){FileName = "in list1", Message = "in l 1"});
list1.Add(new Result(){FileName = "in list2", Message = "in l 2"});
methodData.Parameters.Add(list1);
RecoveryMethodData.SerializeToFile(methodData,#"C:\serialization_result.xml");
}
public class Result
{
public string Message { get; set; }
public string FileName { get; set; }
}
If I do not add list1 into the methodData.Parameters there is no problem serializing the methodDatad object.
One big limitation is that I can't know in advance which kind of objects will be added to the Parameters property (that is why it is a list of objects)
In order to DataContractSerializer to serialize an object, it shall know the types of all datamembers. In your case, you do not define a specific type but an object type. Try changing the definition of
public List<object> Parameters { get; set; }
to something like:
public List<IMyObject> Parameters { get; set; }
Note that, all of your objects which you are trying to add to the parameters list shall inherit IMyObject interface.
Update: I refactored your code up to some point (still in a bad shape) and it seems working, please have a try;
public class Tester
{
public Tester()
{
this.TestSerialization();
}
public void SerializeToFile(RecoveryMethodData recoveryMetaData,string fileName)
{
var encoding = Encoding.UTF8;
using (var fileWriter = new XmlTextWriter(fileName, encoding))
{
fileWriter.Formatting = Formatting.Indented;
// use SharedTypeResolver for deserializing assistance.
var serializer = new DataContractSerializer(typeof(RecoveryMethodData),new List<Type>(){typeof(bool),typeof(Result),typeof(List<Result>)});
serializer.WriteObject(fileWriter,recoveryMetaData);
}
}
private void TestSerialization()
{
var methodData = new RecoveryMethodData();
var result = new Result() { Message = "wow", Pass = true, FileName = "somefile " };
methodData.Add(result);
methodData.Add(true);
var list1 = new List<Result>();
list1.Add(new Result() { FileName = "in list1", Message = "in l 1" });
list1.Add(new Result() { FileName = "in list2", Message = "in l 2" });
methodData.Add(list1);
SerializeToFile(methodData, #"C:\serialization_result.xml");
}
}
public class Result
{
public string Message { get; set; }
public string FileName { get; set; }
public bool Pass { get; set; }
}
public class RecoveryMethodData : List<object>
{
}

Categories

Resources