I am using dynamic ExpandoObject() to create some json required for an NVD3/d3.js visualisation.
The nvd3 library is pretty explicit in what it needs with regards to data identifiers.
Exactly the json i need is the following -
[{
key: "AgeGroups",
values: [{
"label": "<20",
"value": 0
}, {
"label": ">20 <29",
"value": 160
}, {
"label": ">29 <39",
"value": 240
}]
}]
Note: the string 'key' must be lowercase and values must be pluralized.
With the following c#, I am able to get very close -
ageDemoJson.AgeGroups = new object[]
{
new { label = "<20", value = lessThan20 },
new { label = ">20 <29", value = between20and29 },
new { label = ">29 <39", value = between29and39 },
};
This outputs the following
[{
Key: "AgeGroups",
Value: [{
"label": "<20",
"value": 0
}, {
"label": ">20 <29",
"value": 160
}, {
"label": ">29 <39",
"value": 240
}]
}]
With this output, I need to customise the default behaviour of ExpandoObject and make the string 'Key' become 'key' and the string 'value' become 'values'
Is there anyway of doing this?
Of course I can work around this by parsing the json to string and replacing what I need in javascript, but would like if I didn't have to do that.
If you're using asp.net core you can change the JSON serialization by adding this line:
services.AddMvc()
.AddJsonOptions(opts =>
{
// Force Camel Case to JSON
opts.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
});
Or you can achive the same result by using Newtonsoft's Json.NET with this option:
string json = JsonConvert.SerializeObject(
yourObjectToSerialize,
new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() }
);
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')
When getting a JSON with property with :
i.e.
{
"root": {
"sim:names": [{
"name": "Tom"
},
{
"name": "David"
}]
}
}
I'm using Newtonsoft Dynamic parse.
var data = JsonConvert.DeserializeObject<dynamic>(jsonString);
I'm trying to access
data.root.sim:names
But getting compilation error "Invalid expression term ':'"
How can I access it?
You should convert it to object
var data = JsonConvert.DeserializeObject<Object>(jsonString);
And access it like this:
var value = ((JObject)data)["root"]["sim:names"];
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"];
EDITED:
If I load a google spreadsheet using JSON URL into a dynamic C# object, I can't access some entries because the JSON looks like this:
"author": [
{
"name": {
"$t": "XYZ"
},
"email": {
"$t": "XYZ#gmail.com"
}
}
]
Why does the google JSON have $ namespaces? Can we remove them? What can be done?
Here is the code:
var json = new WebClient().DownloadString(#"GoogleUrlWithJson");
dynamic jsonObj = JsonConvert.DeserializeObject(json);
string a = jsonObj.feed.entry[0].author.name.$t; ==> Can't compile error "unexpected $"
Try using square bracket syntax to access the JSON property names that have $ in them:
string a = jsonObj.feed.entry[0].author.name["$t"];