C# Get key/name from JSON children - c#

I am recieving this JSON response from an API:
{
"type": "link",
"title": "One or more validation errors occurred.",
"status": 400,
"traceId": "0000000000000",
"errors": {
"inputNumber": [
"Must be 5 characters."
],
"inputWord": [
"Required."
]
}
}
I am using a profile with AutoMapper to map the response to a model. Here is the code where I'm trying to map the JSON errors property to a Dictionary<string, List<string>> property in my response model:
// Map for Errors property
.AfterMap((src, dest) =>
{
dest.Errors = new Dictionary<string, List<string>>();
var jsonErrorDict = src.SelectTokens("errors").Children();
foreach (var token in jsonErrorDict)
{
// Not working right: Token contains both key and value
var key = token;
var value = new List<string>();
if (token.HasValues)
{
var jsonErrorKeyValues = token.Children();
foreach (JToken innerToken in jsonErrorKeyValues)
{
value.Add(innerToken.ToString());
}
dest.Errors.Add(key.ToString(), value);
}
}
But the token variable contains both the key ("inputNumber" for example) as well as the value ("Must be 5 characters"), so when the mapping is done it looks like this:
"errors": {
"\"inputNumber\": [\r\n \"Must be 5 characters.\"\r\n]": [
"[\r\n \"Must be 5 characters\"\r\n]"
],
"\"inputWord\": [\r\n \"Required\"\r\n]": [
"[\r\n \"Required.\"\r\n]"
}
Im just testing it and getting the response from an escaped string so ignore the escape symbols like \r.
How do I get only the key name?
EDIT:
I added this to the key variable:
var key = token.ToString().Split(':');
And then when I'm adding it to the dest.Errors dictionary I do this:
dest.Errors.Add(key[0], value);
Doesn't feel like the best solution though so alternative solutions are more than welcome.

Related

Reformatting a JSON in C#

I have a JSON response here,
{
"Items": [
{
"Key": {
"timestamp": "2022-11-06T20",
"value": 100.80
}
},
{
"Key": {
"timestamp": "2022-11-07T08",
"value": 100.90
}
}
]
}
That I would like to reformat to this:
{
"Key": [
{
"timestamp": "2019-01-08T20",
"value": 12.44
},
{
"timestamp": "2018-12-12 16:23:00",
"value": 12.45
}
]
}
For all responses, the Key must only be on the top once followed by an array of timestamps and values, and remove the Items parent value completely. I have tried doing this and messing around with the implementation, but I keep receiving multiple different errors. Is this the correct idea to do it or is there a better way to implement this?
JObject obj = JObject.Parse(jsonOutput);
JObject newObj = new JObject();
new JProperty("KEY", new JArray(
.Children<JProperty>()
.Select(j => new JObject(
new JProperty("timestamp", j.Value["timestamp"]),
new JProperty("value", j.Value["value"])
)
)
)
);
jsonOutput = newObj.ToString();
What is the correct way to implement this idea? Thanks!
This can be done very easily by combining
SelectTokens() with a JSONPath wildcard operator for the Items[*] array to select all required JSON objects.
Serialization of an anonymous type object to create the required output structure.
Thus:
var query = obj.SelectTokens("Items[*].Key");
jsonOutput = JsonConvert.SerializeObject(new { Key = query }, Formatting.Indented);
Demo fiddle here.
you can fixed it in one line
jsonOutput = new JObject {new JProperty("Key", ((JArray)JObject.Parse(jsonOutput)
["Items"]).Select(s => s["Key"]))}.ToString();

Json String parse into Dictionary key value pairs c#

I am trying the convert my json string into dictionary but could not successful.
{
"healths": [
{
"serviceName": "UserMgt",
"subService": [
{
"subServiceName": "Base",
"status": 10
},
{
"subServiceName": "Url",
"description": "Url is bad",
"status": 10
},
{
"subServiceName": "Configuration",
"status": 2
}
]
},
{
"serviceName": "ConfigurationMgt",
"subService": [
{
"subServiceName": "url",
"description": "urlis OK!",
"status": 2
},
{
"subServiceName": "Configuration Db",
"status": 2
}
]
}
}...and so son
So, as you see we have a service name, and based on that we have subserviceName then again service name and subservicename.Basiclly i want to convert this into dictionary as a key-value pair so that based on the key(service) we have values subservice(again a key value pair).
I tried many things but does not get a proper result.
like for example using newtonsoft nuget.
JObject jsonObj = JObject.Parse(formattedJson);
Dictionary<string, object> dictObj = jsonObj.ToObject<Dictionary<string, object>>();
foreach(var kv in dictObj)
{
Console.WriteLine(kv.Key + "::::" + kv.Value);
}
In this scenario I am getting output like key as a healths and every thing as a value.
Can anyone please help me regarding this.The Json and c# is new for me.
Thanks In Advance.
Assuming that you are guaranteed to have the described structure, you can deserialize to JObject and use LINQ's ToDictionary to process it:
var dict = JsonConvert.DeserializeObject<JObject>(json)["healths"]
.ToDictionary(
s => s["serviceName"].ToString(),
s => s["subService"]
.ToDictionary(ss => ss["subServiceName"].ToString(), ss => ss["status"].ToString()));
Where you can change ss => ss["status"].ToString() to select what is actually needed as subService value.

How can I $filter on Dictionary<string, string> using OData?

I have an OData query enabled action on my Controller that Returns an Asset.
C# Model.
var asset = new Asset()
{
Id = Guid.NewGuid().ToString(),
Name = "Cool Asset Yo",
Url = "http://test/test.asset",
Tags = new[] {"test"},
Properties = new Dictionary<string, string>
{
{"platform", "android"},
{"dim_depth", "1.0"},
{"dim_height", "1.0"},
{"dim_width", "1.0"},
{"item_type", "Trim"}
}
}
Returned JSON
[
{
"name": "Cool Asset Yo",
"properties": {
"platform": "android",
"dim_depth": "1.0",
"dim_height": "1.0",
"dim_width": "1.0",
"item_type": "Trim"
},
"tags": [
"test"
],
"url": "http://test/test.asset",
"id": "77d9b9df-4f4b-4fad-a1d3-af5075d52a62",
}
]
Example Queries that work!
api/Asset?$filter=startswith(name, 'Cool')
api/Asset?$filter=tags/any(tag eq 'test')
api/Asset?$filter=id eq '77d9b9df-4f4b-4fad-a1d3-af5075d52a62'
And NOW for the fail :-(
api/Asset?$filter=properties/platform eq 'Android'
Error: The parent value for a property access of a property 'platform' is not a single value. Property access can only be applied to a single value.
api/Asset?$filter=properties/any(props: props/platform eq 'Android')
Error: Could not find a property named 'platform' on type 'System.Collections.Generic.KeyValuePair_2OfString_String'.
api/Asset?$filter=properties/any(keyValue: keyValue('platform') eq 'Android')
Error: An unknown function with name 'keyValue' was found. This may also be a function import or a key lookup on a navigation property, which is not allowed.
api/Asset?$filter=properties/any(keyValue: keyValue eq 'Android')
Error: A binary operator with incompatible types was detected. Found operand types 'System.Collections.Generic.KeyValuePair_2OfString_String' and 'Edm.String' for operator kind 'Equal'.
api/Asset?$filter=properties['platform'] eq 'Android'
Error: Syntax error at position 31 in 'properties['platform'] eq 'Android''.
How do I get a list of assets with the 'platform' of 'Android'? I see examples of in the Microsoft Documents of Generic Dictionaries being used in a model, I don't see any $filter examples.
In your scenarios, "Properties" looks a dictionary property, but the dictionary property is not a built-in property in OData.
Besides, your payload looks a normal JSON serialized output. It's not odata payload.
You said you saw examples of in the Microsoft Documents of Generic Dictionaries being used in a model, it's a usage of dynamic property. Please pay attention that "It's different between your scenario (dictionary) and the dynamic property".
Most important, Web API OData now supports to filter on the dynamic property.
See my test cases in the commit
Hope it can help you.
Sam Xu is correct, a dictionary property is not supported in OData, also dynamic property did not work in my scenario. I was forced to change my properties bag to be a list of a custom key-value type.
C# Model.
var asset = new Asset()
{
Id = Guid.NewGuid().ToString(),
Name = "Cool Asset Yo",
Url = "http://test/test.asset",
Tags = new[] {"test"},
Properties = new List<KeyValue>
{
new KeyValue("platform", "android"),
new KeyValue("dim_depth", "1.0"),
new KeyValue("dim_height", "1.0"),
new KeyValue("dim_width", "1.0"),
new KeyValue("item_type", "Trim")
}
}
Returned JSON
[
{
"name": "Cool Asset Yo",
"properties": [
{
"key": "platform",
"value": "android"
},
{
"key": "dim_depth",
"value": "1.0"
},
{
"key": "dim_height",
"value": "1.0"
},
{
"key": "dim_width",
"value": "1.0"
},
{
"key": "item_type",
"value": "Trim"
}
],
"tags": [
"test"
],
"url": "http://test/test.asset",
"id": "77d9b9df-4f4b-4fad-a1d3-af5075d52a62",
}
]
Example Queries that work!
api/Asset?$filter=properties/any(keyValue: keyValue/key eq 'platform' and keyValue/value eq '50129486')

JSON Parsing in C# child members

I am trying to parse JSON data from Instagram API and I am having problem with parsing the child elements. For example, one Instagram response looks like this:
{
"pagination": {
"next_url": "https://api.instagram.com/v1/users/273112457/followed-by?access_token=1941825738.97584da.3242609045494207883c900cbbab04b8&cursor=1439090845443",
"next_cursor": "1439090845443"
},
"meta": {
"code": 200
},
"data": [
{
"username": "ohdyxl",
"profile_picture": "https://igcdn-photos-e-a.akamaihd.net/hphotos-ak-xfp1/t51.2885-19/11093019_661322517306044_2019954676_a.jpg",
"id": "1393044864",
"full_name": "只有你和我知道"
},
{
"username": "dpetalco_florist",
"profile_picture": "https://igcdn-photos-a-a.akamaihd.net/hphotos-ak-xtf1/t51.2885-19/11192809_930052080349888_1420093998_a.jpg",
"id": "1098934333",
"full_name": "D'petalco florist"
}
]
}
My code is the following:
dynamic d = JObject.Parse(response);
foreach (var result in d["data"])
{
string userName = (string)result["username"];
list.Add(userName);
}
This part works perfectly, however when I try to extract pagination, I get a child error access error.
My code is the following:
foreach (var res in d["pagination"])
{
string nexturl = (string)res["next_url"];
string nextcursor = (string)res["next_cursor"];
}
How can I extract the next_url and next_curosr from "pagination" in C#? Thanks.
Unlike data property value, pagination property value is not an array so you don't need foreach loop here :
var res = d["pagination"];
string nexturl = (string)res["next_url"];
string nextcursor = (string)res["next_cursor"];
or without using intermediate variable res :
string nexturl = (string)d["pagination"]["next_url"];
string nextcursor = (string)d["pagination"]["next_cursor"];

Using Dynamic types with JSON in C#

I have an ASP.NET MVC app. I am trying to hit an external web service from the controller in my app. Currently, I am hitting the web service like this:
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(baseAddress);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var response = await client.GetAsync(GetServiceUrl());
dynamic data = System.Web.Helpers.Json.Decode(...)
}
The result from the web service can have three different schemas in JSON. They look like this;
schema 1
{
"request":"some info",
"value": [
{"id":1, name:"bill" },
{"id":2, name:"john" }
]
}
schema 2
{
"request":"some info",
"value": [
{ "orderId":"A12345", orderDate:"10-12-2014" },
{ "orderId":"B31234", orderDate:"11-01-2014" },
{ "orderId":"C36512", orderDate:"12-03-2014" },
]
}
schema 3
{
"request":"some info",
"value": [
{ "productId":"11-22-33", "name":"ball", "description":"a round thing" },
{ "productId":"3A-12-52", "name":"tire", "description":"keeps you moving" },
{ "productId":"7D-xy-23", "name":"plate", "description":"something to eat off of." },
]
}
I would like to avoid writing three separate classes if at all possible. I really only want to do two things: 1) count the number of objects in the value array. 2) Loop through the objects in the value array and print out some of the values via Razor.
Can I do these two things without creating 3 new classes? If so, how?
THank you!
Assuming you're using json.net, you can use JObject and JArray.
var json = #"{'value': [ { 'id' : 1}, { 'id' : 2 } ]}";
var jObject = JObject.Parse(json);
var values = (JArray) jObject["value"];
Console.WriteLine("Number of items: {0}", values.Count);
foreach (var value in values)
{
// do something with value.
}
If you're not using json.net, you could go with Robert Harvey's suggestion and use JavaScriptSerializer.
var jsonDict = serializer.Deserialize<IDictionary<string, object>>(json);
var array = (IEnumerable<object>) jsonDict["value"];

Categories

Resources