Deserialize arbitrary JSON keys and raw values - c#

Using JSON.Net I want to deserialize a JSON object that looks something like this:
"properties": {
"foo": 1,
"bar": "Fred",
"baz": [694481.61, 693638.0, 692624.65, 692354.54]
}
and end up with a dictionary<string,string> that looks like this:
{ "foo", "1" },
{ "bar", "\"Fred\"" },
{ "baz", "[694481.61, 693638.0, 692624.65, 692354.54]" }
The key points to note are:
The keys are not known in advance. (Hence the use of a dictionary rather than deserializing to a class with predefined properties foo, bar and baz.)
The value strings in the dictionary are the raw JSON text from the JSON stream. So strings include their encapsulating quotation marks, and arrays include their encapsulating square brackets.
What I have tried so far
Parse the values as JRaw objects. This would work if I knew the key names in advance: I could declare matching properties in my class as type JRaw - e.g. public JRaw foo { get; set; }. But the key names are not predefined so I can't.
Create a RawValueDictionaryConverter : JsonConverter custom converter that takes the stream and deserializes it directly to a dictionary<string,string>. I thought this would be straightforward, but the raw text of the original stream is not available inside ReadJson(); the stream has already been tokenized and ReadJson() only receives the interpreted token and token type.
Write my own tokenizer and forget about using Json.NET. It may come to this but I don't want to 'reinvent the wheel.'

You can deserialise to Dictionary<string, JRaw> which gets you half way there. For example:
//Example class
public class Root
{
public Dictionary<string, JRaw> properties { get; set; }
}
var json = "<from the question>";
var result = JsonConvert.DeserializeObject<Root>(json);
foreach (var property in result.Properties)
{
var value = property.Value.ToString();
}
If you still want the values as strings, you can convert like this:
var stringDictionary = result.Properties.ToDictionary(p => p.Key, p => p.ToString());

Related

Deserialize a generic JSON and use its properties

I need to call an API that returns a JSON that can vary.
Sometimes the response could be something like:
[
{
"name": "value"
}
]
while other times
[
{
"property": "value"
}
]
or even
[
{
"name": "value",
"status": "value",
"count": "value"
}
]
Basically, I need to retrieve all values in this JSON for later use.
I tried
var prova = JsonConvert.DeserializeObject<dynamic>(result);, but I can't access the properties using ["indexName"] because the index can vary depending on some factors. Any ideas?
You can create a POCO that that has all the possible properties if they are finite. Like the following :
public class Result {
public string name { get; set; }
public string property { get; set; }
public string status { get; set; }
public string count{ get; set; }
}
And then you can use: var prova = JsonConvert.DeserializeObject<IEnumerable<Result>>(Result);. I change the deserialization to using an IEnumerable because I see that your JSON is an array.
And then you can check if the values are null before accessing them. Since every Result object will only have the property that was available in JSON as non-null.
Alternatively, you can use a Dictionary<string, string> or Dictionary<string, int> and do the following :
var prova = JsonSerializer.Deserialize<IEnumerable<Dictionary<string, string>>>(result) as List<Dictionary<string, string>>;
and then you can access every object of the list and access the property you want like this or TryGetValue Method for more safety.
Console.WriteLine(prova[0]["name"]);
Assumption:
You're getting an array of objects from the api (that doesn't return null data - re: probably why the structure is "dynamic").
Here's one way:
//System.Text.Json
var foo = JsonSerializer.Deserialize<JsonElement>(array_from_api);
//It's an array (assumption) of one or more objects
foreach (JsonElement element in foo.EnumerateArray())
{
//iterate through each object's properties
foreach (JsonProperty o in element.EnumerateObject())
{
//Assumption: value isn't a nested object/array, otherwise adjust...
Console.WriteLine($"{o.Name} = {o.Value}");
}
}
//Json.Net
//It's an array (assumption) of one or more objects
JArray deserialized = JsonConvert.DeserializeObject<JArray>(array_from_api);
foreach (JObject jo in deserialized)
{
//iterate through each JObject's properties
foreach (JProperty p in jo.Properties())
{
Console.WriteLine($"{p.Name} = {p.Value}");
}
}
Note: If the structure is more complex - more nesting, you'll have to do some checks and adjust accordingly (re: nested arrays, objects, etc)

Mapping a json array (without keys) to a class object C#

I need some help to map a json array without keys. For examples:
[
"value1",
234,
3034,
"data",
[
"some value",
null,
2020
],
]
I created a class based on these values received, but i'm not able to map to a class object. I just could access this data using a dynamic variable, like:
dynamic object = DataFromJson();
var firstvalues = object[0]; // "value1"
My json is too big with many arrays inside, so accessing with indexes is a big big process.
Does someones know how to access this kind of data and map to a class?
I received a lot of feedbacks regarding that (thanks!), so here is the conclusions:
as a JSON array, this kind of information is not correct to map to a class object. This is not the functional proposal.
JArray can be really helpful to interate between all the information, and then take it to a class. If needed, you could manually create a specific method to include each value in your class object.
Another option is to use a dynamic object, accessing as indexes.
Make sure that this information can not be received in another way, as a JSON with key and values, and map to a class.
If there is some useful update about that, I will edit here.
Well there is one option available, using Cinchoo ETL - an open source library to load such data to objects out of the box.
Define object as below
[ChoSourceType(typeof(object[]))]
[ChoTypeConverter(typeof(ChoArrayToObjectConverter))]
public class foo
{
[ChoArrayIndex(0)]
public long prop1 { get; set; }
[ChoArrayIndex(1)]
public double prop2 { get; set; }
}
Then parse the JSON as below
string json = #"
[
[
1618170480000,
""59594.60000000"",
""59625.00000000"",
""59557.13000000""
],
[
1618170540000
]
]";
using (var r = ChoJSONReader<foo>.LoadText(json))
{
foreach (var rec in r)
Console.WriteLine(ChoUtility.Dump(rec));
}

Need to parse a JSON coming in via a Post request

I am trying to parse a JSON received in a Post request.
The JSON is as follows. It has to be agnostic as to how many records there are or what the fields are called. But the contact variable is always null when I send it via Postman. Is there something wrong with the class I throw it in to?
{
"Fields":
{
"first":"fn",
"last":"ln",
...
}
}
public class FieldsValues
{
List<KeyValuePair<string, string>> Fields = new List<KeyValuePair<string, string>>() { };
}
public void Post([FromBody]FieldsValues Fields)
{
...
}
I want to send the JSON into a Dictionary object but the value coming in is always null.
Your Json is not an array. You need square brackets to build an array.
Besides this the KeyValuePair has members named "Key" and "Value".
To match the List<KeyValuePair<string, string>> you'll need to input something like this:
{
"Fields":
[{
"Key":"first",
"Value":"fn"
}]
}
If you can't change the JSON structure yourself and the structure is really unknown to you, I would go for a method that accepts raw strings and parse that string with Newtonsoft to a dynamic object.
E.g. this code could accept your JSON:
public void Post()
{
string text = "";
using (StreamReader reader = new StreamReader(Request.Body, Encoding.UTF8))
text = reader.ReadToEnd();
dynamic dynObj = JObject.Parse(text);
var firstValue = dynObj.Fields.first.Value;
...
}

How to parse such type of JSON (Nested) in C#

I want to parse such type of json in C#. how to do that if i want to parse "edit", "0001", "Password" and value of "hasParent"?
{
"edit": {
"0001": {
"PKey": [
"Password"
],
"hasParent": 0
}
}
}
Create a JObject from that JSON and access the values like you would with a dictionary. For instance like that
var jObject = JObject.Parse(json);
var innerJObject = JObject.Parse(jObject["0001"]); // there are better ways to do it, just check out the newtonsoft docs
You can also create an object structure and use data annotation
public class MyClass
{
[JsonProperty("edit")]
public MySubClass Subclass { get; set; }
// ... more properties
}
Then just go ahead and use JsonConvert.DeserializeObject<MyClass>(json);

How do I deserialize this JSON?

How do I deserialize the following JSON with Web API (JSON.Net)?:
{
"action": "edit",
"table": "MainView",
"id": "row_1377",
"_group_id": "999",
"data": {
"ROTATION": "1", // This name/val can change
"EQUIPMENT": [{
"id": "6"
},
{
"id": "8"
}],
"NOTES": ""
}
}
The values in data represent columns and can change, so I can't make a set-in-stone object with e.g. a string named "NOTES" as in json.net deserialize string to nested class.
Notice EQUIPMENT contains multiple values. When it was previously just a "string:string" like NOTES, this JSON deserialized data into a Dictionary<string, string>, but now I need it to behave like its own dictionary. My last attempt was to deserialize into the following type:
public class EditorSubmissionJoined
{
public string _group_id { get; set; }
public string action { get; set; }
public string table { get; set; }
public string id { get; set; }
// "public" added below due to mistake noticed by Maggie Ying
public Dictionary<string, object> data { get; set; } // Trouble
}
I was hoping that the object could contain anything in data whether a KeyValuePair (like NOTES) or a dictionary (like EQUIPMENT).
I've also tried Dictionary<string, ICollection<Object>>, Object, and even ICollection<Dictionary<string, Object>>.
The problem is that my controller always gets EditorSubmissionJoined with nothing but null values:
public void Put(EditorSubmissionJoined ajaxSubmission) {
// ajaxSubmission has only NULL values
}
Try setting your 'data' property to public and your JSON should be able to model bind correctly.
There's a few ways you can do it. One way is to simply use a JObject and access the fields by name e.g. : jsonObject["data"]["ROTATION"]. You can "deserialize" that with JObject.Parse and just "parse" the JSON text into a JObject.
Alternatively you can write your own JsonConverter and tell JSON.net to use that converter when deserializing a specific type (e.g. JsonConverterAttribute). This requires parsing parts of the JSON text manually, in the ReadJson override, and really depends on what data you expect.
You can also use the dynamic approach that Preston commented on.
Which approach you pick depends on how strongly-typed you want things to be.

Categories

Resources