I am trying to set a variable for the script scope of IronPython. I want to use a JObject as a Python dictionary. This is what I tried.
ScriptScope scope = engine.CreateScope();
JObject childObject = new JObject();
childObject["child1"] = "test";
JObject dataObject = new JObject();
dataObject["key1"] = childObject;
scope.SetVariable("metaData", dataObject);
I can use the metaData variable, and also use the first key by calling metaData["key1"]. But when I'm trying to get to the next value by calling metaData["key1"]["child1"] I get the following error message: Can not convert from System.String to System.Object. How can I use my JSON Object as if it was a normal Python dictionary? The depth of my JSON Object will vary, so I need to be flexible with that.
Works fine for me.
var engine = Python.CreateEngine();
dynamic scope = engine.CreateScope();
scope.metaData = new JObject
{
["key1"] = new JObject
{
["child1"] = "test",
},
};
engine.Execute(#"
print metaData['key1']['child1']
foo = metaData['key1']
foo['bar'] = 'baz'
print metaData
", scope);
prints:
test
{
"key1": {
"child1": "test",
"bar": "baz"
}
}
It depends on what you're doing with the object within your script.
Just beware that behind the scenes, it is still a plain old json.net JObject, you cannot add any value to it. You cannot add an IronPython dict for instance. It must be something that is or implicitly convertible to a JToken.
Related
I am trying to create structure of nested objects on the flight inside of JsonConverter.WriteObject function.
Data structure:
Container
Object A
Object B
What am I doing wrong?
Can anyone recommend decent guide for writing Custom Converters?
var container = new JObject();
var fi = e.PropertyA;
JObject o = JObject.FromObject(fi);
o.AddFirst(new JProperty("type", new JValue(fi.GetType().Name)));
container.Add(o);
this approach failed with exception
Can not add Newtonsoft.Json.Linq.JObject to Newtonsoft.Json.Linq.JObject
if I do
writer.WriteStartObject();
var fi = e.PropertyA;
JObject o = JObject.FromObject(fi);
o.AddFirst(new JProperty("type", new JValue(fi.GetType().Name)));
o.WriteTo(writer);
writer.WriteEndObject();
'Token StartObject in state ObjectStart would result in an invalid JSON object. Path 'sources[0]'.'
Answer
Thanks to dbc I was able to make it trough with following code
var container = new JObject();
var fi = e.PropertyA;
JObject o = JObject.FromObject(fi);
o.AddFirst(new JProperty("type", new JValue(fi.GetType().Name)));
container.Add(new JProperty("ObjectA", o));
container.WriteTo(writer);
According to the JSON standard a JSON object is an unordered set of name/value pairs so when writing an object you need to do WritePropertyName() before writing a property value:
writer.WritePropertyName("PropertyA");
o.WriteTo(writer);
Similarly when adding a JObject to a JObject you need to nest it in a JProperty to specify the name:
container.Add(new JProperty("PropertyA", o));
The exceptions you are getting reflect the fact that you are trying to add your PropertyA value to a JSON object without first specifying its name.
Working .Net fiddle showing both.
Can anyone tell me why I get an error when trying to output"dJson2.Type" in the code below?
string Json1= #"[{'Id':1, 'FirstName':'John', 'LastName':'Smith'}, {'Id':2, 'FirstName':'Jane', 'LastName':'Doe'}]";
dynamic dJson1= JsonConvert.DeserializeObject(Json1);
Console.WriteLine(dJson1.GetType());
Console.WriteLine(dJson1.Type);
string Json2 = #"{'Id':1, 'FirstName':'John', 'LastName':'Smith'}";
dynamic dJson2 = JsonConvert.DeserializeObject(Json2);
Console.WriteLine(dJson2.GetType());
Console.WriteLine(dJson2.Type);
The program dies on the Console.WriteLine(dJson2.Type) statement. The output of the program is...
Newtonsoft.Json.Linq.JArray
Array
Newtonsoft.Json.Linq.JObject
(should say Object here, I think)
Inspecting the local variables, dJson2 has a "Type" property with value "Object".
This is because JObject behaves similarly as System.Dynamic.ExpandoObject. Try to change your example to:
string Json2 = #"{'Id':1, 'FirstName':'John', 'LastName':'Smith'}";
dynamic dJson2 = JsonConvert.DeserializeObject(Json2);
dJson2.Type = "mynewfield";
Console.WriteLine(dJson2.GetType());
Console.WriteLine(dJson2.Type);
If you want to get property of underlying type you need to cast it (to JToken or JObject), otherwise requested property will be searched in
IDictionary<string, JToken> that JObject implements.
This example may help:
dynamic oobj = new JObject();
oobj.Type = "TEST";
Console.WriteLine(oobj.Type);
Console.WriteLine(((JObject)oobj).Type);
I currently have a REST app which returns a JSON string something like:
[{error: "Account with that email exists"}]
For when an error is thrown. I don't want to deserialize it into a custom "error" object, because it seems a bit wasteful and pointless. Is there a simple way to just extract a specific field out of a JSON string without making a custom class to reflect it.
Thanks
You have a couple of options if you don't want to create a custom class, you can deserialize to dynamic:
dynamic tmp = JsonConvert.DeserializeObject(yourString);
string error = (string)tmp.error;
Or deserialize to a dictionary:
var dic = JsonConvert.DeserializeObject<Dictionary<string, string>>();
string error = dic["error"];
No need third party libraries. Use native JavaScriptSerializer.
string input = "[{error: \"Account with that email exists\"}]";
var jss = new JavaScriptSerializer();
var array = jss.Deserialize<object[]>(input);
var dict = array[0] as Dictionary<string, object>;
Console.WriteLine(dict["error"]);
// More short with dynamic
dynamic d = jss.DeserializeObject(input);
Console.WriteLine(d[0]["error"]);
Have a look at JObject.
dynamic obj = JObject.Parse("{ myerrors: [{error: \"Account with that email exists\"}] }");
var a = obj.myerrors[0];
string error = a.error;
Is it possible to return a dynamic object from a json deserialization using json.net? I would like to do something like this:
dynamic jsonResponse = JsonConvert.Deserialize(json);
Console.WriteLine(jsonResponse.message);
Json.NET allows us to do this:
dynamic d = JObject.Parse("{number:1000, str:'string', array: [1,2,3,4,5,6]}");
Console.WriteLine(d.number);
Console.WriteLine(d.str);
Console.WriteLine(d.array.Count);
Output:
1000
string
6
Documentation here: LINQ to JSON with Json.NET
See also JObject.Parse and JArray.Parse
As of Json.NET 4.0 Release 1, there is native dynamic support:
[Test]
public void DynamicDeserialization()
{
dynamic jsonResponse = JsonConvert.DeserializeObject("{\"message\":\"Hi\"}");
jsonResponse.Works = true;
Console.WriteLine(jsonResponse.message); // Hi
Console.WriteLine(jsonResponse.Works); // True
Console.WriteLine(JsonConvert.SerializeObject(jsonResponse)); // {"message":"Hi","Works":true}
Assert.That(jsonResponse, Is.InstanceOf<dynamic>());
Assert.That(jsonResponse, Is.TypeOf<JObject>());
}
And, of course, the best way to get the current version is via NuGet.
Updated (11/12/2014) to address comments:
This works perfectly fine. If you inspect the type in the debugger you will see that the value is, in fact, dynamic. The underlying type is a JObject. If you want to control the type (like specifying ExpandoObject, then do so.
If you just deserialize to dynamic you will get a JObject back. You can get what you want by using an ExpandoObject.
var converter = new ExpandoObjectConverter();
dynamic message = JsonConvert.DeserializeObject<ExpandoObject>(jsonString, converter);
I know this is old post but JsonConvert actually has a different method so it would be
var product = new { Name = "", Price = 0 };
var jsonResponse = JsonConvert.DeserializeAnonymousType(json, product);
Yes you can do it using the JsonConvert.DeserializeObject. To do that, just simple do:
dynamic jsonResponse = JsonConvert.DeserializeObject(json);
Console.WriteLine(jsonResponse["message"]);
Note: At the time I answered this question in 2010, there was no way to deserialize without some sort of type, this allowed you to deserialize without having go define the actual class and allowed an anonymous class to be used to do the deserialization.
You need to have some sort of type to deserialize to. You could do something along the lines of:
var product = new { Name = "", Price = 0 };
dynamic jsonResponse = JsonConvert.Deserialize(json, product.GetType());
My answer is based on a solution for .NET 4.0's build in JSON serializer. Link to deserialize to anonymous types is here:
http://blogs.msdn.com/b/alexghi/archive/2008/12/22/using-anonymous-types-to-deserialize-json-data.aspx
If you use JSON.NET with old version which didn't JObject.
This is another simple way to make a dynamic object from JSON:
https://github.com/chsword/jdynamic
NuGet Install
PM> Install-Package JDynamic
Support using string index to access member like:
dynamic json = new JDynamic("{a:{a:1}}");
Assert.AreEqual(1, json["a"]["a"]);
Test Case
And you can use this util as following :
Get the value directly
dynamic json = new JDynamic("1");
//json.Value
2.Get the member in the json object
dynamic json = new JDynamic("{a:'abc'}");
//json.a is a string "abc"
dynamic json = new JDynamic("{a:3.1416}");
//json.a is 3.1416m
dynamic json = new JDynamic("{a:1}");
//json.a is integer: 1
3.IEnumerable
dynamic json = new JDynamic("[1,2,3]");
/json.Length/json.Count is 3
//And you can use json[0]/ json[2] to get the elements
dynamic json = new JDynamic("{a:[1,2,3]}");
//json.a.Length /json.a.Count is 3.
//And you can use json.a[0]/ json.a[2] to get the elements
dynamic json = new JDynamic("[{b:1},{c:1}]");
//json.Length/json.Count is 2.
//And you can use the json[0].b/json[1].c to get the num.
Other
dynamic json = new JDynamic("{a:{a:1} }");
//json.a.a is 1.
Yes it is possible. I have been doing that all the while.
dynamic Obj = JsonConvert.DeserializeObject(<your json string>);
It is a bit trickier for non native type. Suppose inside your Obj, there is a ClassA, and ClassB objects. They are all converted to JObject. What you need to do is:
ClassA ObjA = Obj.ObjA.ToObject<ClassA>();
ClassB ObjB = Obj.ObjB.ToObject<ClassB>();
how to add an item to an object initialized with:
object obj = new { blah = "asdf" };
If I want to add another key value pair, how would i?
You can't modify the object's anonymous type definition once you make the object using that initializer syntax. That is, once you initialize it with { blah = "asdf" }, it only has that blah property. You can't add another. This is because anonymous types are static types.
The ExpandoObject answers work though, for a dynamic object. See the other answers for that.
If you're really just trying to manage a collection of key-value pairs (kinda sorta based on the way you phrased your question), use a dictionary.
var kvp = new Dictionary<string, string>
{
{ "blah", "asdf" }
};
kvp.Add("womp", "zxcv");
#BoltClock is right on. Another alternative is to use an ExpandoObject, at the loss of intellisense.
dynamic obj = new ExpandoObject();
obj.blah = "asdf";
// sometime later
obj.somethingelse = "dfgh";
// obj now has 'blah' and 'somethingelse' 'properties'
Once you define an object like that, you're done. You can't add anything to it.
If you're using C# 4.0, though, you could always use a dynamic type:
dynamic obj = new ExpandoObject();
obj.blah = "asdf";
obj.blahBlah = "jkl;";