Create Json using custom attributes in c# using newtonsoft json.net - c#

I would like to create a custom Json object from C# POCO classes, the structure of Json object would be derived from custom attributes applied onto the classes, below is an example of what I am trying to achieve.
Below are few sample classes
public class SomeBaseClass
{
public int BaseId { get; set; }
public string SomeBaseProperty { get; set; }
}
public class NestedClass
{
public string SomeNestedProp1 { get; set; }
public string SomeNestedProp2 { get; set; }
}
[ModelType(TargetModule.COMPLAINT, ModelAffinity.PARENT)]
public class ChildOne : SomeBaseClass
{
public ChildOne()
{
NestedClasses = new List<NestedClass>();
nestedClassesAgain = new List<NestedClass>();
}
public string SomeProperty { get; set; }
public string SomeProperty1 { get; set; }
public string SomeProperty2 { get; set; }
[ModelType(TargetModule.COMPLAINT, ModelAffinity.NESTED)]
public IList<NestedClass> NestedClasses { get; set; }
public IList<NestedClass> nestedClassesAgain { get; set; }
}
Below is a sample custom attribute which is used above.
[Serializable]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property)]
public sealed class ModelType : Attribute
{
public ModelType(TargetModule targetModule, ModelAffinity modelAffinity)
{
TargetModuleName = targetModule;
ModelAffinityType = modelAffinity;
}
public TargetModule TargetModuleName { get; }
public ModelAffinity ModelAffinityType { get; }
}
public enum TargetModule
{
COMPLAINT,
PAYMENT,
RECEIPTS
}
public enum ModelAffinity
{
PARENT,
NESTED,
}
Below is the Json object I plan to create using the custom attributes.
{
"complaint": {
"someproperty": "sample value",
"someproperty1": "sample value1",
"someproperty2": "sample value2",
"baseid": "123",
"somebaseproperty": "sample value3"
"nested": [{
"somenestedprop1": "sample nested value1",
"somenestedprop2": "sample nested value2"
}
],
"nestedclassesagain": [{
"somenestedprop1": "sample nested again value1",
"somenestedprop2": "sample nested again value2"
}]
}
}
In the above output the properties / classes containing custom attribute are converted into their values i.e. the property "NestedClasses" is converted into the attribute value "nested", if the other property "NestedClassesAgain" contained the same attribute then the values / properties would get merged into the "nested" Json Array object.
Something like below
"nested": [{
"somenestedprop1": "sample nested value1",
"somenestedprop2": "sample nested value2"
},
{
"somenestedprop1": "sample nested again value1",
"somenestedprop2": "sample nested again value2"
}
]
Tried achieving this using custom ContractResolver as below
public class AttributeContractResolver : DefaultContractResolver
{
private readonly Dictionary<string, string> configDerivedList;
public AttributeContractResolver()
{
configDerivedList = new Dictionary<string, string>
{
{ "ChildOne", "BaseId,SomeProperty,SomeProperty1,NestedClasses,nestedClassesAgain" },
{ "ChildTwo", "BaseId,SomeBaseProperty,SomeOtherProperty1,SomeOtherProperty2" },
{ "NestedClass", "SomeNestedProp1, SomeNestedProp2"},
{ "COMPLAINT", "BaseId,SomeProperty,SomeProperty1,SomeNestedProp1" },
};
}
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
IList<JsonProperty> properties = base.CreateProperties(type, memberSerialization);
IEnumerable<(ModelType[] attributes, string propWithAttribute)> tt = (from x in base.GetSerializableMembers(type)
where x.GetCustomAttributes(typeof(ModelType), false).Length > 0
let attributes = (ModelType[])x.GetCustomAttributes(typeof(ModelType), false)
let propWithAttribute = x.Name
select (attributes, propWithAttribute));
var moduleType = (ModelType[])type.GetCustomAttributes(typeof(ModelType), false);
List<string> requiredProperties = (from key in configDerivedList
where moduleType.All(mod => mod
.TargetModuleName
.ToString() == key.Key) &&
tt.All(a => a
.attributes
.All(mod => mod
.TargetModuleName
.ToString() == key.Key))
select key).FirstOrDefault().Value.Split(',').ToList();
requiredProperties.AddRange(from propss in properties
from t in tt
where propss.PropertyName == t.propWithAttribute
select propss.PropertyName);
properties = properties.Where(prop => requiredProperties.Contains(prop.PropertyName, new StringComparer())).ToList();
return properties;
}
}
In the sample converter above, I would also like to serialize properties based on the attribute values, i.e. selective properties based on the attributes set on the classes.
Hope I could elaborate the use case.
Thanks in advance.

Related

How to bind property name of the data model object in .net core

I have created a data model class and have another created a property of another class type inside that.
Ex:
public class Properties
{
public string PropertyName { get; set; }
public TypeExt Property { get; set; }
}
public class TypeExt
{
public string DataType { get; set; }
public string DataTypeExt { get; set; }
public string Type { get; set; }
}
Now, when i bind the values, everything works fine except that i need the PropertyName value to come as the Label for Property so that the final Json becomes like this.
{
"Properties":[
{
"Test1Property":{
"DataType":"Unsigned integer ",
"DataTypeExt":"64bit",
"Type":"PM"
}
},
{
"Test2Propert":{
"DataType":"Integer ",
"DataTypeExt":"64bit",
"Type":"PM"
}
}
]
}
One way to get it so you get the PropertyName to be a key is by using a Dictionary as part of your model.
var properties = new Dictionary<string, TypeExt>();
var test1Property = new TypeExt { Type = "PM", DataType = "Integer", DataTypeExt = "64bit" };
var test2Property = new TypeExt { Type = "PM", DataType = "Unsigned Integer", DataTypeExt = "64bit" };
properties.Add("Test1Property", test1Property);
properties.Add("Test2Property", test2Property);
What this results in when serialized is the following. It is a slightly different JSON than what you have above though. Notice that it is no longer an "array-of-objects", but an object that contains properties, each of which are the dictionary keys.
{
"Test1Property" : {
"Type": "PM",
"DataType": "Integer",
"DataTypeExt": "64bit"
},
"Test2Property" : {
"Type": "PM",
"DataType": "Unsigned Integer",
"DataTypeExt": "64bit"
}
}

C# Json.NET Camel Case Complex Object

I'm trying to serialize an object as camelCase and I'm finding that only the objects at the root level are correctly camelCased. Everything below the root level is coming as PascalCase. I'm writing a console application using Json.NET 12.0.3 and .NET Framework 4.0.
public class Deal
{
public string Id { get; set; }
public string Name { get; set; }
public List<PublicId> PublicIds { get; set; }
}
public class PublicId
{
public string IdType { get; set; }
public string Value { get; set; }
}
To serialize I'm using:
var json = JsonConvert.SerializeObject(deal, Formatting.Indented, new JsonSerializerSettings
{
DateFormatString = "yyyy-MM-dd",
ContractResolver = new CamelCasePropertyNamesContractResolver()
});
The result json looks like:
{
"id": null,
"name": "Deal 1",
"publicIds": [
{
"IdType": "ID1",
"Value": "A12"
},
{
"IdType": "ID2",
"Value": "B12"
}
]
}
As you can see the values for IdType and Value are not correctly serialied in camelCase but rather are serialized in PascalCase. There are situations where I'll need to change the serialization between the default PascalCase and camelCase so I won't be able to use JsonProperty annotations to force camelCase during serialization. Additionally I'd like to stick to Json.NET as the only json library for my project.
Is there a clean way to get what I'm looking for?
Firstly I noticed that your Deal class does not initialize PublicIds. In that case the code should actually throw an error.
However, your code that specifies the contract solver CamelCasePropertyNamesContractResolver is correct.
The following is a console code that seems to return proper JSON value.
public class Deal
{
public Deal()
{
PublicIds = new List<PublicId>();
}
public string Id { get; set; }
public string Name { get; set; }
public List<PublicId> PublicIds { get; set; }
}
public class PublicId
{
public string IdType { get; set; }
public string Value { get; set; }
}
Then in the console if the try the code below it seems to yield the desired result.
public static void Main()
{
var deal = new Deal();
deal.Name = "Deal 1";
deal.PublicIds.Add(new PublicId { IdType = "ID1", Value = "A12" });
deal.PublicIds.Add(new PublicId { IdType= "ID2", Value= "B12"});
var json = JsonConvert.SerializeObject(deal, Formatting.Indented, new JsonSerializerSettings
{
DateFormatString = "yyyy-MM-dd",
ContractResolver = new CamelCasePropertyNamesContractResolver()
});
Console.WriteLine(json);
Console.ReadLine();
}
Output by the code:
{
"id": null,
"name": "Deal 1",
"publicIds": [
{
"idType": "ID1",
"value": "A12"
},
{
"idType": "ID2",
"value": "B12"
}
]
}

Json to C# object handling dynamic properties

I am trying to implement the json structure in c# objects and I am trying to understand how I can use the correct object depending on the type. For example:
public class RootObject
{
public string name { get; set; }
public Content content { get; set; }
}
public class Content
{
public string id{ get; set; }
public string type { get; set; }
public Dictionary<string, Item> child { get; set; }
}
public class Item
{
public string id { get; set; }
public string type { get; set; }
public List<string> model { get; set;}
public string[] color {get; set;}
}
Please note this is just an example there are more properties for each object. If Json contains type = "Boy" how can I generate the boy object.
Example JSON:
string json = #"
{
'name': 'Object 1',
'content': {
'body': {
'id': 'body',
'type': 'Body'
},
'style': {
'id': 'style',
'type': 'Style'
},
'DynamicName-123': {
'id': 'DynamicName-123',
'type': 'Row'
'model': {},
'colors': []
},
'DynamicName-434': {
'id': 'DynamicName-434',
'type': 'Column'
'model': {},
'colors': []
},
'DynamicName-223': {
'id': 'DynamicName-223',
'type': 'Item'
'model': {},
'colors': []
}
}
}";
If your key/value pair are not fixed and data must be configurable then Newtonsoft.json has one feature that to be use here and that is [JsonExtensionData] Read more
Extension data is now written when an object is serialized. Reading and writing extension data makes it possible to automatically round-trip all JSON without adding every property to the .NET type you’re deserializing to. Only declare the properties you’re interested in and let extension data do the rest.
In your case, suppose there is a class,
public class MyClass
{
public string Qaz { get; set; }
public string Wsx { get; set; }
[JsonExtensionData]
public Dictionary<string, JToken> child { get; set; }
public MyClass()
{
child = new Dictionary<string, JToken>();
}
}
In the above class, you know that Qaz and Wsx are always present from your json either they contain value or null,
But for dynamic data, you can't say which key/value pair you will receive from your json so the [JsonExtensionData] can collect all those key/value pair in a dictionary.
Suppose the below classes will be for your dynamic data,
public class ABC
{
public string Abc { get; set; }
}
public class PQR
{
public string Pqr { get; set; }
}
public class XYZ
{
public string Xyz { get; set; }
}
Serialization:
ABC aBC = new ABC { Abc = "abc" };
PQR pQR = new PQR { Pqr = "pqr" };
XYZ xYZ = new XYZ { Xyz = "xyz" };
MyClass myClass = new MyClass();
myClass.Qaz = "qaz";
myClass.Wsx = "wsx";
myClass.child.Add("ABC", JToken.FromObject(aBC));
myClass.child.Add("PQR", JToken.FromObject(pQR));
myClass.child.Add("XYZ", JToken.FromObject(xYZ));
string outputJson = JsonConvert.SerializeObject(myClass);
This will give you json like
{
"Qaz": "qaz",
"Wsx": "wsx",
"ABC": {
"Abc": "abc"
},
"PQR": {
"Pqr": "pqr"
},
"XYZ": {
"Xyz": "xyz"
}
}
Deserialization:
MyClass myClass = JsonConvert.DeserializeObject<MyClass>(outputJson);
string Qaz = myClass.Qaz;
string Wsx = myClass.Wsx;
if (myClass.child.ContainsKey("ABC"))
{
ABC abcObj = myClass.child["ABC"].ToObject<ABC>();
}
if (myClass.child.ContainsKey("PQR"))
{
PQR pqrObj = myClass.child["PQR"].ToObject<PQR>();
}
if (myClass.child.ContainsKey("XYZ"))
{
XYZ pqrObj = myClass.child["XYZ"].ToObject<XYZ>();
}
Conclusion: The main aim of [JsonExtensionData] is to keep your json class hierarchy simple and more readable so you don't need to manage class structure for every property.
Get all dynamic data with the specific key in JToken inside Dictionary :
You can use LINQ to fetch all dynamic data of particular key from the above dictionary.
var allAbcTypes = myClass.child
.SelectMany(x => x.Value
.ToObject<JObject>()
.Properties()
.Where(p => p.Name == "Abc") //<= Use "Column" instead of "Abc"
.Select(o => new ABC //<= Use your type that contais "Column" as a property
{
Abc = o.Value.ToString()
})).ToList();
In your case, Its something like,
var allColumnTypes = myClass.child
.SelectMany(x => x.Value
.ToObject<JObject>()
.Properties()
.Where(p => p.Name == "Column")
.Select(o => new Item
{
id = x.Value["id "].ToString(),
type = x.Value["type "].ToString(),
model = x.Value["model"].ToObject<List<string>>(),
color = x.Value["color"].ToObject<string[]>()
})).ToList();
If you want to deserialize to a dictionary with a Key string and a dynamic value (boy or girl in this case), the only way I Know is using Dynamic class:
public List<Dictionary<string, dynamic>> child { get; set; }

Json.net ignore null values of child objects

I am new into json.net, so any help would be appreciated.
I am using the net 2.0 version of json.net, because i need to integrate it in Unity3d engine Suggested answer (using nullvaluehandling) just don't work! Should i consider this as restiction of the oldest version?
So, a have an object like this:
Object ()
{
ChildObject ChildObject1;
ChildObject ChildObject2;
}
ChildObject ()
{
Property1;
Property2;
}
I want json.net to serialize only not null properties of all objects, including child objects. So if i instatiate only property1 of ChildObject1 and property2 of ChildObject2, the string from JsonConvert will be like this:
{
"ChildObject1":
{
"Property1": "10"
},
"ChildObject1":
{
"Property2":"20"
}
}
But default behaviour creates string like this:
{
"ChildObject1":
{
"Property1": "10",
"Property2": "null"
},
"ChildObject2":
{
"Property1": "null,
"Property2":"20"
}
}
I know about NullValueHandling, but it is not working corretly in my case! It ignore only null properties of the parent object (object that we are serializing), but if this parent object has some childs, it will not ignore null properties of this child objects. My situation is different.
If even one property of a child object is not null, it serialize it to a string with one not-null property and others null.
UPD example of my code:
i have nested classes
My object is like this:
public class SendedMessage
{
public List<Answer> Answers { get; set; }
public AnswerItem Etalon {get; set;}
}
public class Answer ()
{
public AnswerItem Item { get; set; }
}
public class AnswerItem ()
{
public string ID { get; set; }
public bool Result { get; set; }
public int Number { get; set; }
}
i instatiate a SendedMessage object like this:
new SendedMessage x;
x.Etalon = new AnswerItem();
x.Etalon.Result = true;
than i use
string ignored = JsonConvert.SerializeObject(x,
Formatting.Indented,
new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
and it make this string:
{ "Etalon": {"ID" = "null", "Result" = "false", Number" = "null"}}
so it really ignore the null object Answers (a List), but do not ignore the null properties of a child objects.
Thanks for help!
use this :
string ignored = sonConvert.SerializeObject(movie,
Formatting.Indented,
new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
here is the example:
public class Movie
{
public string Name { get; set; }
public string Description { get; set; }
public string Classification { get; set; }
public string Studio { get; set; }
public DateTime? ReleaseDate { get; set; }
public List<string> ReleaseCountries { get; set; }
}
static void Main(string[] args)
{
Movie movie = new Movie();
movie.Name = "Bad Boys III";
movie.Description = "It's no Bad Boys";
string included = JsonConvert.SerializeObject(movie,
Formatting.Indented,new JsonSerializerSettings { });
// {
// "Name": "Bad Boys III",
// "Description": "It's no Bad Boys",
// "Classification": null,
// "Studio": null,
// "ReleaseDate": null,
// "ReleaseCountries": null
// }
string ignored = JsonConvert.SerializeObject(movie,
Formatting.Indented,
new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
// {
// "Name": "Bad Boys III",
// "Description": "It's no Bad Boys"
// }
}

How to get an item value of json using C#?

How to get an item value of json using C#?
json:
[{
ID: '6512',
fd: [{
titie: 'Graph-01',
type: 'graph',
views: {
graph: {
show: true,
state: {
group: 'DivisionName',
series: ['FieldWeight', 'FactoryWeight', 'Variance'],
graphType: 'lines-and-points'
}
}
}
}, {
titie: 'Graph-02',
type: 'Graph',
views: {
graph: {
show: true,
state: {
group: 'DivisionName',
series: ['FieldWeight', 'FactoryWeight', 'Variance'],
graphType: 'lines-and-points'
}
}
}
}]
}, {
ID: '6506',
fd: [{
titie: 'Map-01',
type: 'map',
views: {
map: {
show: true,
state: {
kpiField: 'P_BudgetAmount',
kpiSlabs: [{
id: 'P_BudgetAmount',
hues: ['#0fff03', '#eb0707'],
scales: '10'
}]
}
}
}
}]
}]
Above mentioned one is json, Here titie value will be get in a list
please help me...
My code is:
string dashletsConfigPath = Url.Content("~/Content/Dashlets/Dashlets.json");
string jArray = System.IO.File.ReadAllText(Server.MapPath(dashletsConfigPath));
List<string> lists = new List<string>();
JArray list = JArray.Parse(jArray);
var ll = list.Select(j => j["fd"]).ToList();
Here json will be converted in to JArray then
li got fd details then we got tite details on a list
If you just want a List<string> of the "titie" (sic) property values, this should work, using SelectMany:
List<string> result = list.SelectMany(
obj => obj["fd"]
.Select(inner => inner["titie"].Value<string>()))
.ToList()
This assumes that the JSON you posted is made valid by quoting property names.
I would recommend creating a class for your objects and use a DataContractSerializer to deserialize the JSON string.
[DataContract]
public class Container
{
[DataMember(Name="ID")]
public string ID { get; set; }
[DataMember(Name="fd")]
public Graph[] fd { get; set; }
}
[DataContract]
public class Graph
{
[DataMember(Name="title")]
public string Title { get; set; }
[DataMember(Name="type")]
public string Type { get; set; }
}
etc.
This will give you strongly typed classes around your JSON.
I'm not sure how you intend to use the data but you can collect all the titie values from your objects like this:
var arr = JArray.Parse(json);
var query =
from JObject obj in arr
from JObject fd in obj["fd"]
select new
{
Id = (string)obj["ID"],
Titie = (string)fd["titie"],
};
You can use json.net to deserialize json string like this:
public class Item
{
public string ID { get; set; }
public List<FD> fd { get; set; }
}
public class FD
{
public string titie { get; set; }
public string type { get; set; }
public Views views { get; set; }
}
public class Views
{
public Graph graph { get; set; }
}
public class Graph
{
public bool show { get; set; }
public State state { get; set; }
}
public class State
{
public string group { get; set; }
public string[] series { get; set; }
public string graphType { get; set; }
}
class Program
{
static void Main(string[] args)
{
string json = #"..."; //your json string
var Items = JsonConvert.DeserializeObject<List<Item>>(json);
List<string> tities = new List<string>();
foreach (var Item in Items)
{
foreach (var fd in Item.fd)
{
tities.Add(fd.titie);
}
}
}
}
First thing is your json format invalid. get the valid json below.
[{
"ID": "6512",
"fd": [{
"titie": "Graph-01",
"type": "graph",
"views": {
"graph": {
"show": true,
"state": {
"group": "DivisionName",
"series": ["FieldWeight", "FactoryWeight", "Variance"],
"graphType": "lines-and-points"
}
}
}
}, {
"titie": "Graph-02",
"type": "Graph",
"views": {
"graph": {
"show": true,
"state": {
"group": "DivisionName",
"series": ["FieldWeight", "FactoryWeight", "Variance"],
"graphType": "lines-and-points"
}
}
}
}]
}, {
"ID": "6506",
"fd": [{
"titie": "Map-01",
"type": "map",
"views": {
"map": {
"show": true,
"state": {
"kpiField": "P_BudgetAmount",
"kpiSlabs": [{
"id": "P_BudgetAmount",
"hues": ["#0fff03", "#eb0707"],
"scales": "10"
}]
}
}
}
}]
}]
And if you want to read items as separate strings use following code.
JArray jObject = JArray.Parse(json);
var ll = jObject.ToList();
You can use Newtonsoft Json Library.
Deserialize your json string with the model objects below
public class JsonWrapper
{
public string ID { get; set; }
public List<Fd> fd { get; set; }
}
public class Fd
{
public string titie { get; set; }
public string type { get; set; }
public Views views { get; set; }
}
public class Views
{
public Graph graph { get; set; }
}
public class Graph
{
public bool show { get; set; }
public State state { get; set; }
}
public class State
{
public string group { get; set; }
public List<string> series { get; set; }
public string graphType { get; set; }
}
Declare on object of JsonWrapper class and deserialize the json string to it.
JsonWrapper jsonWrapper = new JsonWrapper();
jsonWrapper = (JsonWrapper)JsonConvert.DeserializeObject(jsonString, jsonWrapper.getType());
Then you can access all the lists and properties from the jsonWrapper object.

Categories

Resources