c# dynamic json objects with dynamic names question - c#

Before I get flagged for duplicate, I have the code from Dynamic json object with numerical keys working quite well now. The question with my numeric keys is that unfortunately, the JSON string I am getting is initially delimited by year, so would I use reflection to attempt to create a dynamic property on a dynamic object, and if so how? I know with a dynamic object I can't have obj["2010"] or obj[0]. In JavaScript this is no problem, just trying to get it working in C#. Ideas?
Example of JSON being returned:
{
"2010": [
{
"type": "vacation",
"alloc": "90.00"
},
Alternatively, sometimes the year is the second element as such:
I have no control over this json.
{
"year": [],
"2010": [
{
"type": "vacation",
"alloc": "0.00"
},

Maybe I'm misunderstanding your question, but here's how I'd do it:
static void Main(string[] args) {
var json = #"
{
'2010': [
{
'type': 'vacation',
'alloc': '90.00'
},
{
'type': 'something',
'alloc': '80.00'
}
]}";
var jss = new JavaScriptSerializer();
var obj = jss.Deserialize<dynamic>(json);
Console.WriteLine(obj["2010"][0]["type"]);
Console.Read();
}
Does this help?
I wrote a blog post on serializing/deserializing JSON with .NET: Quick JSON Serialization/Deserialization in C#

I have up-voted the question and JP's answer and am glad I dug around the internet to find this.
I have included a separate answer to simplify my use case for others to benefit from. The crux of it is:
dynamic myObj = JObject.Parse("<....json....>");
// The following sets give the same result
// Names (off the root)
string countryName = myObj.CountryName;
// Gives the same as
string countryName = myObj["CountryName"];
// Nested (Country capital cities off the root)
string capitalName = myObj.Capital.Name;
// Gives the same as
string capitalName = myObj["Capital"]["Name"];
// Gives the same as
string capitalName = myObj.Capital["Name"];
Now it all seems quite obvious but I just did not think of it.
Thanks again.

Related

C# Get JObject inner token

I have this Json structure:
{
"rc": 1,
"msg":
[
{
"msgId": "6661",
"msgTxt": "Invalid Token"
}
]
}
How can I get the 6661 Value? I've tried lots of paths, but it seems those two square brackets are making my day hard
Thanks
Assuming jdoc is your parsed document, then:
var res = jdoc["msg"][0]["msgId"];
should do it (but real code should handle errors as well).
Using JObject parser, you could use :
var obj = JObject.Parse(yourObjectJson);
var value = obj["msg"][0]["msgId"];

Read Dynamic Json

I have a requirement to read the json in which keys are vary and store into dictionary in C#.net. I am using Newtonsoft json. I am deserializing like below.
var inputData = JsonConvert.DeserializeObject<dynamic>(myObj)
If the keys are fixed I can do like below.
var val = inputData.Account;
But here keys are dynamic. Below is my json data.
{
"data": {
"Account": "150.80",
"Name": "XYZ",
"Description": "Some Value"
}
}
Here name value pairs may change. i.e., It may have like below also.
{
"data": {
"Cost": "154.80",
"Type": "S1234",
"Period": "Some Value"
}
}
How to access dynamic keys and store into a dictionary.
EDIT: This answer was for the previous posted question, not the newly revised question... I'm leaving it in, since it probably has some useful details.
I'd recommend using Json.NET to do this.
If the fact that the json data always has the field named data, then you can write fairly predictable code to output the contents of data into a dictionary.
Off the top of my head, I'd probably go for an anonymous type-based deserialization, kind of like this:
var json = #"{
""data"": {
""Account"": ""150.80"",
""Name"": ""XYZ"",
""Description"": ""Some Value""
}
}";
var schema = new { data = new Dictionary<string, object>()};
var result = JsonConvert.DeserializeAnonymousType(json, schema);
You'd have to reach into result.data to get that dictionary.
You could also just use JObject to pull out the values from data directly, but probably would need to parse that data into a dictionary, so it'd be sort of a double call going on, like this:
var jobj = JObject.Parse(json);
var data = jobj["data"];
var dict = JsonConvert.DeserializeObject<Dictionary<string, object>>
(data.ToString());
There's probably more ways to do this even more efficiently. Like I said, these are just ideas off the top of my head.

ASP.NET getting indexed values when deserializing JSON into a dynamic object

So I have a JSON string that I am passing from an AJAX call to my controller. I have a list of indexed values that I am passing into a dynamic object.
I deserialize the JSON with
JsonConvert.DeserializeObject<dynamic>(s)
This is the output from that dynamic object:
"RolePermissions[0].RolePermissionId": "269",
"RolePermissions[0].HasAccess": "false",
"RolePermissions[1].RolePermissionId": "270",
"RolePermissions[1].HasAccess": "false",
"RolePermissions[2].RolePermissionId": "271",
"RolePermissions[2].HasAccess": "true",
"RolePermissions[3].RolePermissionId": "272",
"RolePermissions[3].HasAccess": "false"
When I try to access the a property of the object with
ssObj.RolePermissions[0].RolePermissionId
I get a RuntimeBinderException. I have tried to use JObject.Parse, which works great, but for some reason, the values in the array become out of order.
Any help would be greatly appreciated. Thanks!
When you try to do RolePermissions[0].RolePermissionId you are trying to access a nested collection containing an object with a property RolePermissionId at index 0. But your JSON doesn't represent a hierarchy of objects, it represents a single flat object with key/value pairs whose keys contain periods and brackets. Since c# identifiers don't allow such characters so you have no way to access such property values using dynamic directly.
Instead, your options include:
Take advantage of the fact that JsonConvert.DeserializeObject<dynamic>(s) actually returns a JObject and use its dictionary indexer:
var ssObj = JsonConvert.DeserializeObject<dynamic>(s);
var rolePermissionId = (string)ssObj["RolePermissions[0].RolePermissionId"];
If you prefer a slightly more typed solution, you could deserialize to a Dictionary<string, dynamic>:
var ssDict = JsonConvert.DeserializeObject<Dictionary<string, dynamic>>(s);
var rolePermissionId = (string)ssDict["RolePermissions[0].RolePermissionId"];
Or for a much more statically typed solution, parse explicitly to a JObject and use LINQ to JSON:
var jObj = JObject.Parse(s);
var rolePermissionId = (string)jObj["RolePermissions[0].RolePermissionId"];
Sample fiddle showing the various options.
If you are in control of the data being sent via AJAX then make sure the data sent is properly formatted.
In order to be able to deserialize variable s like:
var ssObj = JsonConvert.DeserializeObject<dynamic>(s);
and access the resulting object in this manner:
ssObj.RolePermissions[0].RolePermissionId
then the JSON value in s, based on your sample and desired behavior, would have to look like this:
{
"RolePermissions": [
{
"RolePermissionId": "269",
"HasAccess": "false"
},
{
"RolePermissionId": "270",
"HasAccess": "false"
},
{
"RolePermissionId": "271",
"HasAccess": "true"
},
{
"RolePermissionId": "272",
"HasAccess": "false"
}
]
}
This quick unit test showed that it is possible to get indexed values when deserializing JSON into a dynamic object
[TestClass]
public class UnitTest1 {
[TestMethod]
public void GetIndexedValuesWhenDeserializingJSONIntoDynamicObject() {
var s = #"
{
'RolePermissions': [
{
'RolePermissionId': '269',
'HasAccess': 'false'
},
{
'RolePermissionId': '270',
'HasAccess': 'false'
},
{
'RolePermissionId': '271',
'HasAccess': 'true'
},
{
'RolePermissionId': '272',
'HasAccess': 'false'
}
]
}
";
var ssObj = JsonConvert.DeserializeObject<dynamic>(s);
var result = ssObj.RolePermissions[0].RolePermissionId;
Assert.AreEqual("269", (string)result);
}
}
So you need to make sure you are sending well formatted JSON to your controller to achieve desired behavior.

Using filters with JsonPath in C#

I'm using JsonPath for C# to query some JSON data. JsonPath doesn't come with its own parser, so as per Rick Sladkey's advice, I'm using Json.NET to parse my Json string into a collection of nested IDictionary objects, IList arrays, and primitives. Then I use JsonPath to filter it (after adding the class suggested in Rick Sladkey's answer).
For reference, here's the part of my code that actually handles all this:
// string exampleJsonString defined below
string query = "$.store.book[*].title" // we should get a list of all titles
// step 1: use Json.NET to parse the json string into a JObject
JObject parsedJson = JObject.Parse(exampleJsonString);
// step 2: use JsonPath with a custom ValueSystem (JsonNetValueSystem)
JsonPathContext context = new JsonPathContext
{ ValueSystem = new JsonNetValueSystem() };
// step 3: get results using JsonPath
List<object> toRet = context.SelectNodes(parsedJson,
query).Select(node => node.Value).ToList();
The reason I was using JsonPath in the first place was because of its filter functionality. You can not only do normal queries like "$.store.book[*].title" (to get an array of all the titles in the book store), but also queries like "$.store.book[?(#.category == 'fiction')].title" (to get an array of all titles in the book store whose category matches 'fiction'). I need to be able to pass entire queries as a string, and so being able to filter while querying is extremely helpful.
Unfortunately, I'm having some trouble getting this filter functionality to work. I expect that I'll have to make adjustments to either the JsonNetValueSystem class (defined originally in the aforementioned stack overflow answer) or the JsonPath namespace (you can get JsonPath.cs from JsonPath's google code page). If there's some external tool or an alternative parsing mechanism to Json.NET that would allow me to keep JsonPath's filtering without having to write too much extra code, that would be ideal, but I'm pretty sure I'll have to alter either JsonNetValueSystem or JsonPath itself. (Both of these are fairly easy to alter since they're just .cs files, but I can't really dig into Json.NET without a lot more work.)
I can't actually seem to figure out where the original JsonPath code handles filtering, nor can I figure out why the JsonNetValueSystem class robs it of that functionality. Any advice for how to add the ability to filter in the query string would be very much appreciated. Even if it's just "don't mess with JsonPath, just change JsonNetValueSystem" or vice versa.
string exampleJsonString = "{
"store": {
"book": [ {
"category": "reference",
"author": "Nigel Rees",
"title": "Sayings of the Century",
"price": 8.95
}, {
"category": "fiction",
"author": "Evelyn Waugh",
"title": "Sword of Honour",
"price": 12.99
}, {
"category": "fiction",
"author": "Herman Melville",
"title": "Moby Dick",
"isbn": "0-553-21311-3",
"price": 8.99
}, {
"category": "fiction",
"author": "J. R. R. Tolkien",
"title": "The Lord of the Rings",
"isbn": "0-395-19395-8",
"price": 22.99
} ],
"bicycle": [ {
"color": "red",
"price": 19.95,
"style": [ "city", "hybrid" ]
}, {
"color": "blue",
"price": 59.91,
"style": [ "downhill", "freeride" ]
} ]
}
}"
When you use the script expression in a query (the ?(...) part), you need to provide a ScriptEvaluator method to evaluate the script. Unfortunately they don't provide a default implementation for the C# version. You'll need to provide that implementation.
Out of the box, this won't be the most trivial problem to solve, you'll need to write an interpreter. You have a couple of options: use CodeDOM to compile and execute the script as C# code (or any language you would prefer), use Roslyn to parse the script and evaluate, whatever works.
A quick and dirty solution for this particular case would be to do something like this in your script evaluator method:
object EvaluateScript(string script, object value, string context)
{
if (script == "#.category == 'fiction'")
{
var obj = value as JObject;
return (string)obj["category"] == "fiction";
}
return null;
}
Here's another solution which utilizes IronPython to evaluate the script.
public class IronPythonScriptEvaluator
{
private Lazy<ScriptEngine> engine = new Lazy<ScriptEngine>(() => Python.CreateEngine());
private ScriptEngine Engine { get { return engine.Value; } }
private const string ItemName = "_IronPythonScriptEvaluator_item";
public object EvaluateScript(string script, object value, string context)
{
var cleanScript = CleanupScript(script);
var scope = Engine.CreateScope();
scope.SetVariable(ItemName, value);
return Engine.Execute<bool>(cleanScript, scope);
}
private string CleanupScript(string script)
{
return Regex.Replace(script, #"#", ItemName);
}
}
Another solution is to use Manatee.Json instead. It has a native JSONPath implementation and parser all built in (along with schema and a serializer). Moreover, you aren't required to represent the path as a string. Manatee.Json has a fluent interface that you can use to build paths, including expression support.
To represent $.store.book[*].title, you would have
var path = JsonPathWith.Name("store")
.Name("book")
.Array()
.Name("title");
For your example $.store.book[?(#.category == 'fiction')].title, you'd use
var path = JsonPathWith.Name("store")
.Name("book")
.Array(jv => jv.Name("category") == "fiction")
.Name("title");
What's more is that there is limited support for fields within those expressions as well.
If your path source is a string, Manatee.Json handles path parsing, too!

converting graph api for xml

I'm having trouble converting a string of json facebook graph api, I used the facebook C# and json.Net.
But at conversion time it returns this error: Name can not begin with the '0 'character, hexadecimal value 0x30.
This is the code:
dynamic result = await _fb.GetTaskAsync ("me / feed");
FBxml JsonConvert.DeserializeXNode string = (result.ToString ()). ToString ();
It looks like there is a problem with portion of the json string as mentioned below (taken from your link http://jsfiddle.net/btripoloni/PaLC2/)
"story_tags": {
"0": [{
"id": "100000866891334",
"name": "Bruno Tripoloni",
"offset": 0,
"length": 15,
"type": "user"}]
},
Json cannot create class that begins with a numeric value such as '0'. Try creating the classes using the link http://json2csharp.com/ you will get an idea.
To solve this problem you can create a dynamic object and go through each properties OR create a JsonConverter and write your code in the ReadJson to convert the "0" to a meaningful name. May be this can help you http://blog.maskalik.com/asp-net/json-net-implement-custom-serialization
If this is not your problem then update the question with more information like class structure of FBxml, call stack of the exception (from which line of the json code is throwing the exception), Json version etc.
As keyr says, the problem is with those JSON properties that have numeric names. In XML names can contain numeric characters but cannot begin with one: XML (see the Well-formedness and error-handling section).
My idea was to recursively parse the JSON with JSON.Net, replacing properties that had numeric names:
var jsonObject = JObject.Parse(json);
foreach (var obj in jsonObject)
{
Process(obj.Value);
}
XDocument document = JsonConvert.DeserializeXNode(jsonObject.ToString());
....
private static void Process(JToken jToken)
{
if (jToken.Type == JTokenType.Property)
{
JProperty property = jToken as JProperty;
int value;
if (int.TryParse(property.Name, out value))
{
JToken token = new JProperty("_" + property.Name, property.Value);
jToken.Replace(token);
}
}
if (jToken.HasValues)
{
//foreach won't work here as the call to jToken.Replace(token) above
//results in the collection modifed error.
for(int i = 0; i < jToken.Values().Count(); i++)
{
JToken obj = jToken.Values().ElementAt(i);
Process(obj);
}
}
}
This seemed to work well, prefixing numeric names with _. At this line:
XDocument document = JsonConvert.DeserializeXNode(jsonObject.ToString());
it crashed with an error saying that invalid/not well formed XML had been created. I don't have the actual error with me, but you can run the above code to replicate it.
I think from here you may need to revisit converting the JSON to XML in the first place. Is this a specific requirement?

Categories