How to construct object programmatically inside of JsonConverter WriteObject - c#

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.

Related

How to deserialize json where type of properties not fixed - can be empty string or an object, please suggest. how to handle this situation?

I have to process the JSON object returned by an API response.
I tried by creating expando object and than adding all the properties to it.
and than copying the value to it.
dynamic dPropertyLinkValue = new ExpandoObject();
dPropertyLinkValue.link = "";
dPropertyLinkValue.value = "";
I am expecting a better way to do this, without expando object.
You can deserialize JSON by casting it to dynamic object. Please refer below sample:
Here deserializing Json to dynamic object and after that loop through its properties and in that you can check you value that whether it is object or not.
string jsonText = "{a:'testString',b:{'prop1':'value1'}}";
var jObj = JsonConvert.DeserializeObject<dynamic>(jsonText);
foreach (JProperty property in jObj)
{
string text = property.Name + " : " + property.Value;
//Here you can check whether property.Value is Jobject or any other value
}

String date property of object is deserialized to another format even though it should remain unchanged [duplicate]

Here is the code:
string s = "2012-08-08T01:54:45.3042880+00:00";
JObject j1 = JObject.FromObject(new
{
time=s
});
Object o = j1["time"];
We can check that o is string and equals "2012-08-08T01:54:45.3042880+00:00"
Now we transfer j1.ToString() to another program, which is
{
"time": "2012-08-08T01:54:45.3042880+00:00"
}
then at the other program, try to parse it back to JObject, which is
JObject j2 = JObject.Parse(j1.ToString());
Object o2 = j2["time"];
Now, if we check o2, o2's type is Date, o2.ToString() is 8/7/2012 9:54:45 PM.
My question is:
Is there is way to disable the Date deserialization for JObject.Parse , and just get the raw string?
Thanks in advance
When parsing from an object to JObject you can specify a JsonSerializer which instructs how to handle dates.
JObject.FromObject(new { time = s },
new JsonSerializer {
DateParseHandling = DateParseHandling.None
});
Unfortunately Parse doesn't have this option, although it would make sense to have it. Looking at the source for Parse we can see that all it does is instantiate a JsonReader and then passes that to Load. JsonReader does have parsing options.
You can achieve your desired result like this:
using(JsonReader reader = new JsonTextReader(new StringReader(j1.ToString()))) {
reader.DateParseHandling = DateParseHandling.None;
JObject o = JObject.Load(reader);
}
For background, see Json.NET interprets and modifies ISO dates when deserializing to JObject #862, specifically this comment from JamesNK: I have no plans to change it, and I would do it again if give the chance.
You can accomplish this using JsonConvert.DeserializeObject as well, by using JsonSerializerSettings:
string s = "2012-08-08T01:54:45.3042880+00:00";
string jsonStr = $#"{{""time"":""{s}""}}";
JObject j1 = JsonConvert.DeserializeObject<JObject>(jsonStr, new JsonSerializerSettings {DateParseHandling = DateParseHandling.None});

Create IronPython dictionary from JObject

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.

Getting a specific field from a JSON string without deserializing in C#

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;

JObject how to read values in the array?

This is the json string:
{"d":[{"numberOfRowsAdded":"26723"}]}
string json = DAO.getUploadDataSummary();
JObject uploadData = JObject.Parse(json);
string array = (string)uploadData.SelectToken("d");
How do I change the code to reader the values in 'numberOfRowsAdded?
JObject uploadData = JObject.Parse(json);
int rowsAdded = Convert.ToInt32((string)uploadData["d"][0]["numberOfRowsAdded"])
You need to cast to JArray:
string json = "{\"d\":[{\"numberOfRowsAdded\":\"26723\"}]}";
JObject parsed = JObject.Parse(json);
JArray array = (JArray) parsed["d"];
Console.WriteLine(array.Count);
You can cast your JObject as a dynamic object.
You can also cast your array to JArray object.
JObject yourObject;
//To access to the properties in "dot" notation use a dynamic object
dynamic obj = yourObject;
//Loop over the array
foreach (dynamic item in obj.d) {
var rows = (int)item.numberOfRowsAdded;
}
I played around with writing a generic method that can read any part of my json string. I tried a lot of the answers on this thread and it did not suit my need. So this is what I came up with. I use the following method in my service layer to read my configuration properties from the json string.
public T getValue<T>(string json,string jsonPropertyName)
{
var parsedResult= JObject.Parse(json);
return parsedResult.SelectToken(jsonPropertyName).ToObject<T>();
}
and this is how you would use it :
var result = service.getValue<List<string>>(json, "propertyName");
So you can use this to get specific properties within your json string and cast it to whatever you need it to be.

Categories