JSON string is unexpectedly deserialized into object as a list - c#

This JSON:
{
"Values": {
"Category": "2",
"Name": "Test",
"Description": "Testing",
"Expression": "[Total Items] * 100"
}
}
Is being deserialized to this DTO using JsConfig.ConvertObjectTypesIntoStringDictionary = true;:
public class MyDto {
public Dictionary<string, object> Values { get; set; }
}
Unexpectedly, the Expression property is deserialized as List<object> instead of string (see screenshot).
It seems the parser sees the opening bracket and tries to interpret the value as an array. Is there some way to turn this "type detection" off, or otherwise resolve the problem (without changing the DTO)?
I'm using ServiceStack v3.9.71.

Json.NET is able to deserialize your example JSON into an instance of your DTO class. It seems that the JSON parsing library you're using is buggy. Are you able to switch?
internal class Program
{
private static void Main()
{
const string json = #"{
""Values"": {
""Category"": ""2"",
""Name"": ""Test"",
""Description"": ""Testing"",
""Expression"": ""[Total Items] * 100""
}
}";
var myDto = JsonConvert.DeserializeObject<MyDto>(json);
}
}
public class MyDto
{
public Dictionary<string, object> Values
{
get;
set;
}
}
EDIT:
I switched my code to use ServiceStack.Text from NuGet and I was able to get the serialization to work perfectly:
var myDto = JsonSerializer.DeserializeFromString<MyDto>(json);

Related

How can I deserialize JSON when the object type is not known beforehand?

So I have an API and front-end that I am developing, and I need a way to deserialize JSON when one of the values could be a List of multiple different types. Currently I'm deserializing it into a List<dynamic> but that's a huge pain to work with in my context.
public class WorkbenchAPI
{
public string status { get; set; }
public HttpStatusCode code { get; set; }
public string error { get; set; }
public string guid { get; set; }
public List<dynamic> results { get; set; }
}
Sample JSON
{
"status": "ok",
"code": 200,
"error": null,
"guid": "1234",
"results": [
{
"SamAccountName": "dizbuster",
"CN": "Buster, Diz",
"EmailAddress": "dizbuster#whatever.com",
}
]
}
In the above example JSON, results should be deserialized into type List<ClassA> for example.
{
"status": "ok",
"code": 200,
"error": null,
"guid": "1234",
"results": [
{
"data": "127.0.0.1",
"owner": "dizbuster",
"email": "dizbuster#whatever.com",
},
{
"data": "192.168.0.1",
"owner": "dizbuster",
"email": "dizbuster#whatever.com",
}
]
}
Where as in this sample, results should be deserialized into List<ClassB>.
Some of the field names may show up in different types, but some are not. Functionally they are two different types representing the outputs from two separate API calls, so I'd like to have it deserialize into specific object types as opposed to using dynamic or a monolithic object that contains every possible field.
Currently I'm taking the List<dynamic> and serializing it back into a temporary JSON string, then deserializing it again into the List<ClassA> or whatever. This seems like a bad way to do it, and is cumbersome to work with.
Is there a better way to structure this or to handle the serialization/deserialization? I have full control over both ends so it's not too difficult for me to alter the JSON as well if needed. Also, I know that a particular API call will return JSON that looks like this, while another API call will return JSON that looks like that. Each case should result in a differently typed list
Since you know in advance what type of data is being returned in "results" for each API call, you can make your WorkbenchAPI class generic:
public abstract class WorkbenchAPI
{
protected abstract IReadOnlyCollection<dynamic> GetResults();
public string status { get; set; }
public HttpStatusCode code { get; set; }
public string error { get; set; }
public string guid { get; set; }
public IReadOnlyCollection<dynamic> results => GetResults();
}
public class WorkbenchAPI<T> : WorkbenchAPI where T : class
{
protected override IReadOnlyCollection<dynamic> GetResults() => results;
public new List<T> results { get; set; } = new List<T>();
}
Notes:
I extracted the common properties into an abstract base class to allow them to be accessed by pre-existing non-generic code that does not care about the specific type of result.
I also added a IReadOnlyCollection<dynamic> results to the base class to ease integration with pre-existing code, e.g.:
// Deserialize to the concrete, known type
var root = JsonConvert.DeserializeObject<WorkbenchAPI<ClassA>>(json);
// Access the results in a type-safe manner:
var accounts = root.results.Select(r => r.SamAccountName).ToList();
// Upcast to the base class in code where we don't need to know about the specific result type.
// E.g.: accessing root properties like guid or getting the result count.
WorkbenchAPI baseRoot = root;
var count = baseRoot.results.Count;
var guid = baseRoot.guid;
However, adding access to the results as a non-generic read-only collection of dynamic objects is optional, and could be removed if your legacy code can be rewritten to be generic.
Demo fiddle here: https://dotnetfiddle.net/lbTs1z

Deserializing JSON issue

I need to deserialize just part of a JSON string returned from a server. The 'myData' portion in the JSON string below.
My JSON string is structured as follows.
{
"data": {
"CODE": {
"someData": {
"h": "foo",
"id": "City",
"lat": "11.11111"
},
"feedMe": [
[
{
"myData": {
"item1": "a",
"item2": "b",
"item3": "c"
},
"moreData": {}
}
]
]
}
}
}
In Unity there is the JSONutility.FromJson method
https://docs.unity3d.com/ScriptReference/JsonUtility.FromJson.html
but unsure how I would either
1 pass only the 'myData' portion to this method.
or
2 Deserialize the entire string
An alternativ to using JsonUtility there is good old SimpleJSON which allows you to only access a certain field of your json like e.g.
var N = JSON.Parse(the_JSON_string);
var myData = N["data"]["CODE"]["feedMe"][0][0];
var item2 = myData["item2"].Value;
In general the simplest way to get the needed c# class structure for your json is always using json2csharp and make all classes [Serializable] and remove the {get; set;} in order to use fields instead of properties. Something like this
[Serializable]
public class SomeData
{
public string h;
public string id;
public string lat;
}
[Serializable]
public class CODE
{
public SomeData someData;
public List<List<MyData>> feedMe;
}
[Serializable]
public class MyData
{
public string item1;
public string item2;
public string item3;
}
[Serializable]
public class Data
{
public CODE CODE;
}
[Serializable]
public class RootObject
{
public Data data;
}
Instead of List<T> you can also use T[] if you like. And the class names actually don't matter but the structure and field names have to match.
and then use
var root = JsonUtility.FromJson<RootObject>(THE_JSON_STRING);
var myData = root.data.CODE.feedMe[0][0];
var item2 = myData.item2;
As already comented however there is a nested array in your array .. not sure if this is intended.
well, use one of the powerful json nuget -newtonsoft.json , then in your code you can iterate the values like below
var files = JObject.Parse(YourJSON);
var recList = files.SelectTokens("$..data").ToList();
foreach (JObject obj in recList.Children())
{
foreach (JProperty prop in obj.Children())
{
var key = prop.Name.ToString();
var value = prop.Value.ToString();
//Do your stuffs here
}
}
JsonUtility not work whit json files, this only for save and load basic public variables of some class. Asset Store have many frameworks for parse json. p.s. your json is strange, [] its array and you have feedMe:[[{myData, moreData}]]. One array whene just one object in array... parse confusing.

How can I return my object property name as node name

I am stuck while returning api result, I have a class like
public partial class Sample
{
[JsonProperty("classificator")]
public List<Classificator> Classificator { get; set; }
}
public partial class Classificator
{
[JsonProperty("Value")]
public string Value { get; set; }
[JsonProperty("Description")]
public string Description { get; set; }
}
Let's say GetJson method retrieve our data from the database, there are 2 records and the data like
-- Value - Description
1- A - AXA
2- B - BXA
response = GetJson(); // this method gets data from db
return Content(HttpStatusCode.OK, response);
when I return this, it's like
{
"classificator": [{
"Value": "A",
"Description": "AXA"
}, {
"Value": "B",
"Description": "BXA"
}
]
}
but I would like to see like, I want to see bellowing result;
{
"classificator": [{
"A": "AXA"
}, {
"B" : "BXA"
}
]
}
I would like to ask you maybe someone knows a good practice or document(tutorial) about it.
I solve it by using, Dictionary < string, model >
but I need to return a huge nested field I cant implement this solution for all different nodes.
I solved by using Dictionary< string, object >
I put 2 nested objects inside of an object value. In my case it looked some complex I refactor and try to work through readable dictionary hierarchy.
basically for this example it something like below,
Dictionary<string, object> fooDict = new Dictionary<string, object>();
fooDict.Add("A", "AXA"); // in my case I put 2 nested object to value field
fooDict.Add("B", "BXA");
var serializedObject = JsonConvert.SerializeObject(fooDict);
using (System.IO.StreamWriter file = new System.IO.StreamWriter(#"C:\xxx\result.txt", true))
{
file.WriteLine(serializedObject);
}

Deserialize array in JSON into class/object

I'm trying to store JSON data into a class. I could deserialize my otherJSON string into class by: var ser = JsonConvert.DeserializeObject<ClsResult>(myJSON); before I got stuck with array.
{
\"Test\": [{
\"FirstBool\":1,
\"aString\":\"hello\"
}]
}
This is my class for JSON:
public class Test
{
[JsonProperty("FirstBool")]
public bool FirstBool { get; set; }
[JsonProperty("aString")]
public string aString { get; set; }
}
public class ResultObject
{
[JsonProperty("Test")]
public List<Test> Test { get; set; }
}
How I deserialize my non-array JSON:
var ser = JsonConvert.DeserializeObject<ResultObject>(myJSON);
What changes do I need to make it work again?
Edited answer
Your json string as I've noticed later contains object named Test which is basically an array of objects ( object[] ).
As you can see from the json string :
{
"Test": [{
"FirstBool" : 1,
"aString" : "hello"
}]
}
[ means that json object begins an array type and ] means that json object ended an array type.
{ means that json object begins an object type and } means that json object ended an object type.
Which in your case will require to make kind of a custom deserializer using existing methods from Newtonsoft.Json library.
Example for the Test object could be :
JObject obj = JObject.Parse(jsonString);
// now your obj contains field named "Test" that is of type object[]
// to retrieve informations you have to select "Test" token
JToken testToken = obj.SelectToken("Test");
// your token contains now something like " [{ "FirstBool" : 1, "aString" : "hello" }]"
// which basically is an array
// meaning that you have to iterate through this
foreach(var child in token.Children())
{
// and convert it to a Test object
Test test = JsonConvert.DeserializeObject<Test>(child.ToString());
// test now is fully deserialized object
}
Deserialize it as a list:
JsonConvert.DeserializeObject<List<Test>>(json);
...instead of a wrapper object.

C# JSON Parse gives error 'System.ArgumentNullException' when parsing JSON array

I'm trying to parse this JSON:
{"error":[],"result":{"XETHXXBT":{"a":["0.023769","64","64.000"],"b":["0.023756","42","42.000"],"c":["0.023756","1.21518360"],"v":["74038.22109284","130984.00945101"],"p":["0.023689","0.006974"],"t":[1272,2332],"l":["0.023440","0.023440"],"h":["0.024091","0.024669"],"o":"0.024084"}}}
The piece of data I want to get is
"c":["0.023756","1.21518360"],
More to the point, the first value of "c". The code I am using is:
JObject jObject = JObject.Parse(json);
double balance = (double)jObject["c"];
What am I doing wrong? How can I just get the first value of the "c" array?
Thanks!
Here is the full error report: http://pastebin.com/4S204aUG
To get to c do the following:
var o = JObject.Parse(<yourjsontext>);
var result = o["result"];
var XETHXXBT = result["XETHXXBT"];
var c = XETHXXBT["c"];
var value1 = (double) c[0];
var value2 = (double) c[1];
Your problem is that your object is more complicated than it looks.
The answer is jObject['results']['XETHXXBT']['c'][0] or jObject['results']['XETHXXBT']['c'][1]. Take a look at it with a prettifier.
{
"error":[
],
"result":{
"XETHXXBT":{
"a":[
"0.023769",
"64",
"64.000"
],
"b":[
"0.023756",
"42",
"42.000"
],
"c":[
"0.023756",
"1.21518360"
],
"v":[
"74038.22109284",
"130984.00945101"
],
"p":[
"0.023689",
"0.006974"
],
"t":[
1272,
2332
],
"l":[
"0.023440",
"0.023440"
],
"h":[
"0.024091",
"0.024669"
],
"o":"0.024084"
}
}
}
As you can see, your base object does not have a c property, so naturally it is throwing an error when you attempt to access (and automatically type cast) that nonexistent property.
Use Like that it will give you more flexibility to get the data , if you don't know how may level depth you have to search it will become very difficult and code will be look like tightly coupled or hardcoded whenever you working with json or xml follow class structure it will help to debug or understand the structure as well
public class Test {
public string[] error { get; set; }
public string result { get; set; }
}
public class Result {
public List<Values> XETHXXBT { get; set; }
}
public class Values {
public List<Double> a { get; set; }
public List<Double> b { get; set; }
public List<Double> c { get; set; }
}
After that class Jsonconvert.deserializeObject<Test>(jsonString); and store it in object you will proper json data in object and after that you can traaverse and get desired data according to your need.Hope it will help you T
Thanks

Categories