is it Microsoft's Json (System.Runtime.Serialization.Json) bug? - c#

i'm working with Microsoft Json library. (DataContractJsonSerializer)
i thought it was a nice library but it caught very hard problem for me.
first, please see the screenshot please.
the json file was clear. because i test it some online json parse sites like here
a problem is it'cant deserialize json rightly. it was cracked.
i. terms[0].labels=null. but as web parser showed, it contains 'labels' structure.
ii. terms1.labels!=null. but as web parser showed, it contains nothing. (terms1 doesn't 'labels' structure, instead terms[0]
a problem is not only that.
the 'primaries' contains number of two array originally, but microsoft json returns just one member only.
even, terms1.labels[0].text have a string value "[US]" but, a string "[US]" is not exist in entire json string!
here is my structure for json.
[DataContract]
public struct GDicJson
{
[DataMember] public string query;
[DataMember] public string sourceLanguage;
[DataMember] public string targetLanguage;
[DataMember] public List<GDicResultContent> primaries;
[DataMember] public List<GDicResultContent> webDefinitions;
[DataContract]
public struct GDicResultContent
{
[DataMember] public string type;
[DataMember] public List<GDicResultTerm> terms;
[DataMember] public List<GDicResultEntry> entries;
}
[DataContract]
public struct GDicResultTerm
{
[DataMember] public string type;
[DataMember] public string text;
[DataMember] public string language;
[DataMember] public List<GDicResultLabel> labels;
}
[DataContract]
public struct GDicResultLabel
{
[DataMember] public string text;
[DataMember] public string title;
}
[DataContract]
public struct GDicResultEntry
{
[DataMember] public string type;
[DataMember] public List<GDicResultTerm> terms;
[DataMember] public List<GDicResultEntry> entries;
}
}
i like to my source json file but StackOverflow doesn't provide upload file. i'm sorry for that.
anyway, help me anybody.
if you want, i'll send a json file to your email with my source code.

But still as suggested by #StriplingWarrior, Json.NET has some issues too. I had a correct Json string containing basically just arrays within squared brackets and Json.NET was unable to parse it correctly and was returning nulls. I used fastJSON instead and all problems were solved. Plus is a way faster library than Json.NET. Give it a look at http://www.codeproject.com/KB/IP/fastJSON.aspx it also pretty easy to implement.

This is just a guess but it could be that because you're using structs, it's not updating instance's field upon deserialization. Can you change these to be classes instead of structs and try it out?

Related

C# Json Generic "Tiered" Deserialize

I'm trying to deserialize a JSON file into a generic stack of serialized objects so I can easily make a sort of tree view using a for loop.
I've done a little Googling over the past couple hours but can't seem to find anything that would allow a truly generic approach, as all seem to require using pre-declared variables, setting the max depth of the tree.
There are many online generic JSON viewers (though no code is provided) so I am sure this is possible, I just have no idea how.
The file I'm currently working with as an example is below, as is an example of how I'm trying to get this structured.
{"arcanePrefs":[{"name":"playerWalkingSpeed","category":"player","value":"6"},{"name":"playerRunningSpeed","category":"player","value":"8"},{"name":"playerLookSpeed","category":"player","value":"12"},{"name":"playerHorTurnSpeed","category":"player","value":"2"},{"name":"playerVerTurnSpeed","category":"player","value":"2"},{"name":"playerJumpHeight","category":"player","value":"6"},{"name":"playerVertLimit","category":"player","value":"80"},{"name":"playerAirCtrl","category":"player","value":"True"},{"name":"playerGravMod","category":"player","value":"1.5"},{"name":"playerHBobWlkSpd","category":"player","value":"0.18"},{"name":"playerHBobRunSpd","category":"player","value":"0.35"},{"name":"playerHBobHgt","category":"player","value":"0.4"},{"name":"playerHCant","category":"player","value":"True"},{"name":"playerReloadSpeed","category":"player","value":"1"},{"name":"playerUseRadius","category":"player","value":"0.5"},{"name":"playerWasteHealth","category":"player","value":"False"},{"name":"playerWasteArmor","category":"player","value":"False"},{"name":"playerWasteAmmo","category":"player","value":"False"},{"name":"playerHeight","category":"player","value":"1.6"},{"name":"playerBaseHealth","category":"player","value":"100"},{"name":"playerMaxHealth","category":"player","value":"250"},{"name":"playerbaseArmor","category":"player","value":"100"},{"name":"playerMaxArmor","category":"player","value":"150"},{"name":"playerWeaponSoftDrag","category":"player","value":"True"},{"name":"enemyStunLock","category":"enemy","value":"True"},{"name":"enemyGunshotDetectRaduis","category":"enemy","value":"40"},{"name":"worldWaterFallDmg","category":"world","value":"False"},{"name":"worldCanShootSwitches","category":"world","value":"True"},{"name":"worldLavaDamagePerFrame","category":"world","value":"1"},{"name":"cameraFOV","category":"camera","value":"80"},{"name":"cameraToneMapping","category":"camera","value":"True"},{"name":"cameraCustomPixel","category":"camera","value":"True"},{"name":"cameraPixelRes","category":"camera","value":"res360p"},{"name":"cameraDither","category":"camera","value":"True"},{"name":"cameraDitherStrength","category":"camera","value":"0.95"},{"name":"cameraBloom","category":"camera","value":"True"},{"name":"cameraBloomInt","category":"camera","value":"5"},{"name":"cameraUnderwaterCol1","category":"camera","value":"0.1921569;0.3921569;0.4509804;1"},{"name":"cameraUnderwaterCol2","category":"camera","value":"0.3137255;0.5882353;0.5882353;1"},{"name":"cameraUnderlavaCol1","category":"camera","value":"0.9019608;0.2313726;0;1"},{"name":"cameraUnderlavaCol2","category":"camera","value":"0.9019608;0.6666667;0.3529412;1"},{"name":"cameraCshrCol","category":"camera","value":"0.4901961;0.4901961;0.4901961;1"},{"name":"cameraCshrTgtCol","category":"camera","value":"0.7803922;0;0;1"},{"name":"arcaneLimitFPS","category":"engine","value":"True"},{"name":"arcaneFpsLimit","category":"engine","value":"-1"},{"name":"engineUIScale","category":"engine","value":"0.7"},{"name":"srcBHopping","category":"sem","value":"False"}],"arcaneControls":[{"name":"contForward","key":119},{"name":"contLeft","key":97},{"name":"contBackward","key":115},{"name":"contRight","key":100},{"name":"contRotLeft","key":113},{"name":"contRotRight","key":101},{"name":"contJump","key":32},{"name":"contLookUp","key":280},{"name":"contLookDown","key":281},{"name":"contSprintHold","key":304},{"name":"contSprintToggle","key":301},{"name":"contCrouchHold","key":306},{"name":"contCrouchToggle","key":99},{"name":"contComFire","key":323},{"name":"contComFireAlt","key":305},{"name":"contComSFire","key":324},{"name":"contComSFireAlt","key":303},{"name":"contComReload","key":114},{"name":"contComPrevWeap","key":326},{"name":"contComNextWeap","key":327},{"name":"contComInspectWeap","key":103},{"name":"contDebug","key":96}]}
What I'm trying to do
I do not use Unity, but they seem to provide newtonsoft which is a powerfull serializer / deserializer library for json link
For your use case, you want to convert json to a list of objet I think, so deserialize in this case.
To obtain an object representation of your json string you can go like
string json; // you data here
Arcane arcane=Newtonsoft.Json.JsonConvert.DeserializeObject<Arcane>(json);
public class Arcane
{
public List<ArcanePref> arcanePrefs { get; set; }
public List<ArcaneControl> arcaneControls { get; set; }
}
public class ArcanePref
{
public string name { get; set; }
public string category { get; set; }
public string value { get; set; }
}
public class ArcaneControl
{
public string name { get; set; }
public int key{ get; set; }
}
With the arcane object you can then access the acranePrefs and arcaneControls list.
To represent the json data in a tree view fashion with Unity, I found the tree view api
Which seem the most straight foward way to go for a tree view representation
Once you have your objects, it should be more or less simple.
Concerning riffnl comment, I do not have any idea what the end goal is, or what is the source you are using ^^'
Hope it helps !

How can I deserialize this specific json string?

I am trying to deserialize the following json string using Newtonsoft Json. I am able to get the string successfully, but when I try using JsonConvert.DeserializeObject<ServerList>(response, settings);, the try catch fails.
[
{"endpoint":"127.0.0.1","id":6,"identifiers":["steam:","license:","xbl:","live:","discord:"],"name":"Blurr","ping":160},
{"endpoint":"127.0.0.1","id":7,"identifiers":["steam:","license:","xbl:","live:","discord:"],"name":"Knight","ping":120}
]
I believe my issue is because the players array being unnamed.
I have tried [JsonProperty("")] and [JsonProperty] for the Users var, I have also tried using List and Array instead of IList.
Here is the object. This may be completely wrong, I have tried many ways of doing this.
public class ServerList
{
// I have tried many ways of doing this array/list. This is just the latest way I tried.
[JsonProperty]
public static IList<Player> Users { get; set; }
}
public class Player
{
[JsonProperty("endpoint")]
public static string Endpoint { get; set; }
[JsonProperty("id")]
public static string ServerId { get; set; }
[JsonProperty("identifiers")]
public static IList<string> Identifiers { get; set; }
[JsonProperty("name")]
public static string Name { get; set; }
[JsonProperty("ping")]
public static int Ping { get; set; }
}
I am expecting to get a 'ServerList' object returned with a list of all the players connected to the server.
Ask any questions you need to, I don't often work with json in this format. Thank you in advance!
ERROR: Error reading JObject from JsonReader. Current JsonReader item is not an object: StartArray. Path '', line 1, position 1.
Simplest way: Your json is an array, so deserialize to an array:
JsonConvert.DeserializeObject<Player[]>(response,settings);
As noted in the comments, properties on the Player should not be static.
If you insist on an object structure similar to what you posted, an object with a Usersproperty, even though it's not present in the JSON, that is also possible, by implementing a custom JSON converter. There's an article with an example of that here: https://www.jerriepelser.com/blog/custom-converters-in-json-net-case-study-1/
HOWEVER; I would recommend sticking to the types present in the json, and perhaps later construct the object that makes sense to the model in your program. This way, what you deserialize are true to the json you are getting, but make no sacrifices on the model you'd like:
var players = JsonConvert.DeserializeObject<Player[]>(response,settings);
var serverList = new ServerList {Users = players};

Auto-generate C# classes from JSON, including property initializers

There are a number of great ways to auto-generate C# code from JSON, such as here and here.
However, the resulting code doesn't include property initializers. For example, the following JSON:
{
"Name" : "Blastoise"
}
gets deserialized to this:
public class RootObject
{
public string Name { get; set; }
}
Presumably this is by design, since the values used in the JSON will probably be overridden anyways, so adding initializers might just annoy people who don't want them.
But what if I want that? Short of manually adding every value by hand, is there a way to deserialize JSON to the following?
public class RootObject
{
public string Name { get; set; } = "Blastoise";
}
Obviously in this case a manual edit is easy, but manual editing becomes tedious for larger JSON objects.
is there a way to deserialize JSON to the following?
Using the source code of the converter you mentioned.
A quick change at the line 204
sw.WriteLine(prefix + "public {0} {1} {{ get; set; }} = {2};", field.Type.GetTypeName(), field.MemberName, field.GetExamplesText());
gives me the result similar to what you described
internal class SampleResponse1
{
[JsonProperty("Name")]
public string Name { get; set; } = "Blastoise";
}

How to Deserialize XML elements to generic list with unknown element names

I am retrieving and successfully deserializing an xml string from a database table column for the known element names (these do not change) but there are also some nested XML Elements called "Other Attributes" which are not always going to be known. I'm having some trouble deserialising these unknown element names to a generic list so I can display them in html once deserialised.
The XML is as follows:
<Detail>
<DetailAttributes>
<Name>Name_123</Name>
<Type>Type_123</Type>
</DetailAttributes>
<OtherAttributes>
<SummaryKey AttributeName="SummaryKey">SummaryKey_123</SummaryKey>
<Account AttributeName="Account">Account_123</Account>
</OtherAttributes>
</Detail>
I have no problem deserialising the 'Name' and 'Type' elements and I can deserialise the 'SummaryKey' and 'Account' elements but only if I explicitly specify their element names - which is not the desired approach because the 'OtherAttributes' are subject to change.
My classes are as follows:
[XmlRoot("Detail")]
public class objectDetailsList
{
[XmlElement("DetailAttributes"), Type = typeof(DetailAttribute))]
public DetailAttribute[] detailAttributes { get; set; }
[XmlElement("OtherAttributes")]
public List<OtherAttribute> otherAttributes { get; set; }
public objectDetailsList()
{
}
}
[Serializable]
public class Detail Attribute
{
[XmlElement("Type")]
public string Type { get;set; }
[XmlElement("Name")]
public string Name { get;set; }
public DetailAttribute()
{
}
}
[Serializable]
public class OtherAttribute
{
//The following will deserialise ok
//[XmlElement("SummaryKey")]
//public string sumKey { get; set; }
//[XmlElement("Account")]
//public string acc { get; set; }
//What I want to do below is create a list of all 'other attributes' without known names
[XmlArray("OtherAttributes")]
public List<Element> element { get; set; }
}
[XmlRoot("OtherAttributes")]
public class Element
{
[XmlAttribute("AttributeName")]
public string aName { get; set; }
[XmlText]
public string aValue { get; set; }
}
When I try to retrieve the deserialised list of OtherAttribute elements the count is zero so it's not able to access the elements nested within "Other Attributes".
Can anybody help me with this please?
With concrete classes and dynamic data like this, you won't be able to lean on the standard XmlSerializer to serialize / deserialize for you - as it reflects on your classes, and the properties you want to populate simply don't exist. You could provide a class with all possible properties if your set of 'OtherAttributes' is known and finite, and not subject to future change, but that would give you an ugly bloated class (and I think you've already decided this is not the solution).
Practical options therefore:
Do it manually. Use the XmlDocument class, load your data with .Load(), and iterate the nodes using .SelectNodes() using an XPath query (something like "/Detail/OtherAttributes/*"). You will have to write the lot yourself, but this gives you complete control over the serialization / deserialization. You won't have to cover your code in (arguably superfluous!) attributes either.
Use Json.NET (http://james.newtonking.com/json), it allows for far greater control over serialization and deserialization. It's fast, has good docs and is overall pretty nifty really.

How to deserialize variable size JSON string with variable names

Deserializing a small, fixed size, fixed structure, with fixed field names, JSON string is easy: Just define a class that contains all the fields (with correct types and names, all known at compile time).
Deserializing a variable-size of repeating nested pairs, is somewhat more challenging but can be done with the help of a List<> inside the class.
But what do I do when the name of the fields are unknown at compile time? e.g.:
{
"container":{
"GD01AB491103":{
"field_id1":11,
"field_id2":12,
"field_id3":13,
"field_id4":"fourteen"
},
"DC01AB491103":{
"field_id1":21,
"field_id2":22,
"field_id3":23,
"field_id4":"twenty four"
},
"GH01AB451101":{
"field_id1":31,
"field_id2":32,
"field_id3":33,
"field_id4":"thirty four"
}
.
.
.
},
"terminator"
}
How to deserialize such a string?
(preferably with .NET's JavaScriptSerializer but if it's too weak/incapable, I might need to resort to something else)
Edit: To clarify the nature of the challenge: In the example above, in order to define a class:
public class ??????
{
public int field_id1 {get;set;}
public int field_id2 {get;set;}
public int field_id3 {get;set;}
public string field_id4 {get;set;}
}
I need to query the JSON string first, then at runtime build classes (reflection?) with these variable-name class objects in it? Looks too cumbersome... Perhaps there is a saner way?
Or maybe the class/field names are irrelevant to .NET's JavaScriptSerializer and all matters is the type? (and correct structure of course)
You can do this probably more simply than you think.. your ?????? class can be anything..
public class GenericObject
{
public int field_id1 {get;set;}
public int field_id2 {get;set;}
public int field_id3 {get;set;}
public string field_id4 {get;set;}
}
and then deserialize the root of the object graph into an object that contains a Dictionary<string,GenericObject>...
public class SomeContainer
{
public Dictionary<string,GenericObject> container {get;set;}
}
you can then loop over the values of the dictionary if you don't care about the names of the keys.

Categories