What is equivalent C# class to generate following JSON? - c#

I want following JSON result to use in highstock pie chart.
[['John', 63.0163],['Depp', 19.2422],['Carla', 6.4767],['Santa', 0],['Tim', 11.2647]]
I tried to make List<ChartSeries> of below object having string and double properties
public class ChartSeries
{
public string Person { get; set; }
public double Percent { get; set; }
}
but using Newtonsoft.JSON it serialize and give below result which shows class properties names which will not be accepted by highstock pie chart.
[{"Person":"John", "Percent":63.0163},{"Person":"Depp", "Percent":19.2422},{"Person":"Carla", "Percent":6.4767},{"Person":"Santa", "Percent":0},{"Person":"Tim", "Percent":11.2647}]
Thanks in advance

Try transforming your data and serializing the output.
internal static class Extensions
{
public static IEnumerable<dynamic> Transform(this IEnumerable<ChartSeries> data)
{
foreach (var chartSeries in data)
{
var result = new ExpandoObject() as IDictionary<string, object>;
result.Add(chartSeries.Person, chartSeries.Percent);
yield return result;
}
}
}
Haven't tried it but serializing the dynamics collection should do the trick.

Related

How to get all not exist keys after JsonConvert DeserializeObject in Json.Net?

Hello I'm using NewtonSoft Json.Net to deserialize my json data. I usually deserialize json string but I want to check all of not exist keys.
For example here is a json data.
{
"Hp": 100,
"PlayerInfo": {
"Atk": 10,
"Def": 20
},
"Mp": 100
}
And I have a structure which can match above data.
[Serializable]
public struct CharaData
{
public int Hp;
[Serializable]
public struct PlayerInfoData
{
public int Atk;
public int Def;
public int Spd;
}
PlayerInfoData PlayerInfo;
}
And I'm gonna deseialize it like this.
JsonConvert.DeserializeObject<CharaData>(jsonStr);
There is a Mp key in json data but in structure there is not.
And in PlayerInfoData there is no Spd key in json data but in structure there is a Spd field.
Well... Spd field seems initialize as a default 0 value and it could potentially be a bug.
So I want to check what keys are not in structure.
And what structure fields are not deserialized because of not exist.
I will do my best to prevent these happening, but if some keys are missing in the process of deserializing from json data, I will log to find the problem why deserialize wasn't
completely success.
[Error][CharaData::Mp key not exist in json string]
[Error][CharaData::PlayerInfo::Spd field not exist in struct]
Seems there is no any method to check it in JsonConvert class.
I saw
[JsonProperty(Required = Required.Always)]
but this does not check all of keys.
Is this need to write a custom json converter?
use this code
var result= JsonConvert.DeserializeObject<CharaData>(jsonStr);
var mp=result.Mp;
var playerInfo=result.PlayerInfo;
if you want to know what key are exist just check them for null. By default all keys are null. if they are not null, it means they took value from json. For example you can use this code
if (mp==null) Console.WriteLine ("mp is not exist in json");
another way is to use reflection to check all properties
var props = result.GetType().GetProperties();
var nulls = new List<string>();
foreach (var prop in props)
{
var propInstance = prop.GetValue(result, null);
if (propInstance == null) nulls.Add(prop.Name);
if (prop.Name == "PlayerInfo")
{
var prps = prop.PropertyType.GetProperties();
foreach (var prp in prps)
if (prp.GetValue(propInstance, null) == null) nulls.Add(prop.Name+"."+prp.Name);
}
}
foreach (var n in nulls)
Console.WriteLine(n + " doesn't have value");
test result
PlayerInfo.Spd doesn't have value
classes
public class PlayerInfo
{
public int? Atk { get; set; }
public int? Def { get; set; }
public int? Spd { get; set; }
}
public class CharaData
{
public int? Hp { get; set; }
public PlayerInfo PlayerInfo { get; set; }
public int? Mp { get; set; }
}
Your problem is twofold:
Find the missing fields
Find the extra fields
Before we are digging into the details let's split the CharaData into two classes
[Serializable]
public class CharaData
{
public int Hp;
public PlayerInfoData PlayerInfo;
}
[Serializable]
public class PlayerInfoData
{
public int Atk;
public int Def;
public int Spd;
}
Missing Fields
This solution relies on the JsonSchema
private static Lazy<JSchema> schema = new Lazy<JSchema>(() => {
var generator = new JSchemaGenerator();
return generator.Generate(typeof(CharaData));
}, true);
public static void ReportMissingFields(string json)
{
var semiParsed = JObject.Parse(json);
try
{
semiParsed.Validate(schema.Value);
}
catch (JSchemaValidationException ex)
{
Console.WriteLine(ex.ValidationError.Message);
}
}
schema stores the json schema of CharaData in a lazy fashion
Validate compares the json against the schema and if there is a mismatch then it throws a JSchemaValidationException
It exposes a property which type is ValidationError which contains a lots of information about the mismatch
Extra fields
This solution relies on JsonExtensionDataAttribute
[Serializable]
internal class CharaDataExtras: CharaData
{
[JsonExtensionData]
public IDictionary<string, JToken> ExtraFields;
}
...
public static void ReportExtraFields(string json)
{
var result = JsonConvert.DeserializeObject<CharaDataExtras>(json);
foreach (var field in result.ExtraFields)
{
Console.WriteLine($"An extra field has found, called {field.Key}");
}
}
I've defined the CharaData as class to be able to derive from it << CharaDataExtras
Every extra field will be put into the ExtraFields dictionary
Usage
var json = File.ReadAllText("sample.json");
ReportMissingFields(json);
ReportExtraFields(json);
The output:
Required properties are missing from object: Spd.
An extra field has found, called Mp

How can i see if my JSON contains a certain value and then compare it?

var Name = "Resources.myjson.json";
var NameJSON = new System.IO.StreamReader(typeof(Strings).GetTypeInfo().Assembly.GetManifestResourceStream(Name)).ReadToEnd();
var ParsedBrandJSON = Newtonsoft.Json.JsonConvert.DeserializeObject<TheInfo>(NameJSON);
await JsonCS.LoadJson(ParsedBrandJSON);
And on the page:
static public class TheInfoJSON
{
static public TheInfo Data { get; set; }
static public async Task LoadJson(Data JSON)
{
Data = JSON;
}
}
and
public class TheInfo
{
public List<TheName> TheName { get; set; } = new List<TheName>();
}
My json:
{
"TheInfo":[
{
"TheName": ["Martin", "Jonas", "Alex", "Oscar"]
}
]
}
When i now try to compare how can i see if my JSON contains a certain object and then store that as a single TheName? Is it possible to do it in the same cast?
var TheNameDataFromOtherPage = OtherPage.TheName; //Here i gather the name from another page that i will compare with the JSON
//Wrong syntax
bool DoTheyMatch = TheNameDataFromOtherPage == TheInfoJSON.Data.TheName.Contains("Alex");
This is now wrong syntax because i cant compare the value to a bool. How can i get out the data i find and then instead of having TheInfoJSON.Data.TheName.Contains("Alex"); as a bool, back to a single value of TheName containing "Alex" so I can create a bool out of the two values to see if the JSON has it or not.
I tried to add something along the lines like this after the contains(): as TheInfo.TheName but that isnt the correct syntax either.
bool DoTheyMatch = TheInfoJSON.Data.TheName.Contains(TheNameDataFromOtherPage);

Serialize list of objects

I need to serialize/deserialize some XML code and part of it looks like next example:
<CoordGeom>
<Curve rot="cw" chord="830.754618036885" crvType="arc" delta="72.796763873948" dirEnd="283.177582669379" dirStart="355.974346543327" external="169.661846548051" length="889.38025007632" midOrd="136.562611151675" radius="699.999999998612" tangent="516.053996536113">
<Start>4897794.2800513292 6491234.9390137056</Start>
<Center>4897096.0071489429 6491185.7968343571</Center>
<End>4897255.5861026254 6491867.3645547926</End>
<PI>4897758.0514541129 6491749.7197593488</PI>
</Curve>
<Spiral length="109.418078418008" radiusEnd="INF" radiusStart="699.999999999025" rot="cw" spiType="clothoid" theta="4.477995782709" totalY="2.849307921907" totalX="109.351261203955" tanLong="72.968738862921" tanShort="36.493923980983">
<Start>4897255.5861026254 6491867.3645547936</Start>
<PI>4897220.0531303799 6491875.6840722272</PI>
<End>4897147.9238984985 6491886.7208634559</End>
</Spiral>
<Spiral length="153.185309785019" radiusEnd="499.99999999993" radiusStart="INF" rot="ccw" spiType="clothoid" theta="8.776871734087" totalY="7.808812331497" totalX="152.826239431476" tanLong="102.249348442205" tanShort="51.176160975293">
<Start>4897147.9238985004 6491886.7208634559</Start>
<PI>4897046.8509311257 6491902.186455016</PI>
<End>4896998.0370401107 6491917.5553683294</End>
</Spiral>
<Curve rot="ccw" chord="936.510896488672" crvType="arc" delta="138.94725576785" dirEnd="66.423714388543" dirStart="287.476458620693" external="925.970149937768" length="1212.543549877849" midOrd="324.680762068264" radius="499.999999999181" tangent="1335.436583485725">
<Start>4896998.0370401107 6491917.5553683294</Start>
<Center>4897148.1939981515 6492394.4755796343</Center>
<End>4896948.2091376046 6492852.7397562303</End>
<PI>4895724.243644949 6492318.6055583945</PI>
</Curve>
</CoordGeom>
I've generated automatically classes using xsd.exe. Part of generated code looks like this:
public partial class CoordGeom
{
private List<object> _items;
private List<Feature> _feature;
private string _desc;
private string _name;
private stateType _state;
private string _oID;
public CoordGeom()
{
_feature = new List<Feature>();
_items = new List<object>();
}
[XmlElementAttribute("Chain", typeof(Chain))]
[XmlElementAttribute("Curve", typeof(Curve))]
[XmlElementAttribute("IrregularLine", typeof(IrregularLine))]
[XmlElementAttribute("Line", typeof(Line))]
[XmlElementAttribute("Spiral", typeof(Spiral))]
public List<object> Items
{
get { return this._items; }
set { this._items = value; }
}
[XmlElement("Feature")]
public List<Feature> Feature { get; set; }
[XmlAttribute()]
public string desc { get; set; }
[XmlAttribute()]
public string name { get; set; }
[XmlAttribute()]
public stateType state { get; set; }
[System.Xml.Serialization.XmlAttributeAttribute()]
public string oID
{
get{ return this._oID; }
set{ this._oID = value; }
}
}
And my code for deserialization look like this:
XmlSerializer mySerializer = new XmlSerializer(typeof(LandXML), new XmlRootAttribute(""));
TextReader myFileStream = new StreamReader("myFile.xml");
LandXML myObject = (LandXML)mySerializer.Deserialize(myFileStream);
var coordGeomItems = myObject.Alignments.Alignment[0].CoordGeom;
My problem is that, when I deserialize file, it is deserialized as list of items of type {LandXML.Curve}, {LandXML.Spiral} etc. and I don't know how to access their properties. It would be great if I can do this directly. Here is a screenshot:
EDIT 1
Here is inital screen
then I have items:
When I unfold this
And this is at the top layer of object - it has some InnerXml, InnerText... If I want to achieve CoordGeom, there is a lot object.Item(i).ChildNodes.Item(j).ChildNodes...
And all of that is because in some lines, lists of objects are made like List as for CoordGeom
Because there are multiple allowed types, the Items collection is typed as object. The simplest approach is to enumerate and cast each item:
foreach(var item in coordGeomItems.Items)
{
var curve = item as Curve;
if (curve != null)
{
// access curve properties here
}
var spiral = item as Spiral
if (spiral != null)
{
// access spiral properties here
}
// ...
}
You could build up a list of Curves and Spirals and access them using properties with custom getters:
class CoordGeom
{
public List<object> Items;
List<Curve> _curves;
public List<Curve> Curves
{
get
{
return _curves ?? (_curves = Items
.Where(item => item is Curve).Select(curve => (Curve)curve).ToList());
}
}
}
The null coalescing operator (??) will cause the Curves property to set and return the value of _curves as a list of curves if _curves is null. This basically causes it to initialize the list on the first get and on all subsequent gets it will return the already initialized list.
As you cannot change the generated class nor the XML.The best possible approach would be to write an extension method.
public static List<Curve> GetCurves(this CoordGeom cg)
{
return cg.Items.OfType<Curve>().ToList();
}
public static List<Spiral> GetSpirals(this CoordGeom cg)
{
return cg.Items.OfType<Spiral>().ToList();
}
Once you do this, you can get items like this
var coordGeomItems = myObject.Alignments.Alignment[0].CoordGeom;
var curves = coordGeomItems.GetCurves();
var spirals = coordGeomItems.GetSpirals();

Deserializing Complex Json Object to Dictionary

I am having some trouble deserializing a Json string to use in an api wrapper I am currently writing. This is the json string in question:
{
"Search":[
{
"Title":"Clerks.",
"Year":"1994",
"imdbID":"tt0109445",
"Type":"movie"
},
{
"Title":"Clerks II",
"Year":"2006",
"imdbID":"tt0424345",
"Type":"movie"
}
]
}
This is the method I am currently using to process it.
public static Dictionary<string, string> FetchTitlesListDictionary(string searchQuery)
{
string searchResult = SendRequest(new[] { "?s=", searchQuery });
JObject parser = JObject.Parse(searchResult);
var movieDictionary = new Dictionary<string, string>();
for (int i = 0; i < parser["Search"].Count(); i++)
{
if (!movieDictionary.ContainsKey((string)parser["Search"][i]["imdbID"]))
{
movieDictionary.Add((string)parser["Search"][i]["imdbID"],
(string)parser["Search"][i]["Title"]);
}
}
return movieDictionary;
}
Even though the code above works, I feel it could, somehow, be made simpler.
How would I go about achieving this?
Thanks!
var obj = JsonConvert.DeserializeObject<RootObject>(searchResult);
public class Search
{
public string Title { get; set; }
public string Year { get; set; }
public string imdbID { get; set; }
public string Type { get; set; }
}
public class RootObject
{
public List<Search> Search { get; set; }
}
If you really want to convert the RootObject to a dictionary, you can use
var movieDictionary = obj.Search.ToDictionary(s => s.imdbID, s => s.Title);
PS: see this site
Well, if you're open to not using the default serializer, I would just open up the package manager console and type
Install-Package ServiceStack.Text
Then it becomes as easy as
var myDictionary = JsonObject.Parse(myJsonString)
.ArrayObjects("Search")
.ToDictionary(key => key.Get("imdbID"), value => value.Get("Title"));
There might be a similar and just as simple way to do it with the newtonsoft serializer, but honestly I never use it, so i'm not sure.
Also same thing as EZI's answer, it's also really easy if you have the objects he created, then you can just
var myObject = myJsonString.FromJson<RootObject>();
//if you want the dictionary it's the same thing, standard linq
var dictionary = myObject.Search.ToDictionary(x => x.imdbId, x => x.Title);
but if all you need is a dictionary, I would just use the above method, it's fast and easy.

ISerializable - serialise a recursive object type eg, a Map

I am trying to create a web service using WCF and C# to present some data to an AJAX client.
I would like my data to return like so (JSON):
{"Settings":{"LAN":{"IPAddress":"10.0.0.1", "SubnetMask":"255.255.255.0"},"WAN":{"Status":"Up"}}}
I have created a simple JsonMap class as such:
[Serializable]
public class JsonMap :ISerializable
{
Dictionary<string, JsonMap> children { get; set; }
public string Value { get; set; }
public JsonMap()
{
this.children = new Dictionary<string, JsonMap>();
this.Value = string.Empty;
}
public JsonMap this[string key]
{
get
{
if (!this.children.ContainsKey(key))
this.children[key] = new JsonMap();
return this.children[key];
}
set
{
this.children[key] = value;
}
}
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
foreach (string key in this.children.Keys)
if (this[key].children.Keys.Count == 0)
info.AddValue(key, this[key].Value);
else
info.AddValue(key, this[key]);
}
}
In theory, as the JsonMap class is serialized it should check if the children are also parents, and render them if so - or render the child's value.
However - when running this through WCF it crashed out and I get no-data returned.
Am I missing something obvious here?
This is how I serialize to Json, it doesnt answer your question and may be useless, but may help.. so just in case:
System.Web.Script.Serialization.JavaScriptSerializer o = new System.Web.Script.Serialization.JavaScriptSerializer();
string JsonString = o.Serialize(MyObject);

Categories