I'm receiving a JSON string in a MVC4/.NET4 WebApi controller action. The action's parameter is dynamic because I don't know anything on the receiving end about the JSON object I'm receiving.
public dynamic Post(dynamic myobject)
The JSON is automatically parsed and the resulting dynamic object is a Newtonsoft.Json.Linq.JContainer. I can, as expected, evaluate properties at runtime, so if the JSON contained something like myobject.myproperty then I can now take the dynamic object received and call myobject.myproperty within the C# code. So far so good.
Now I want to iterate over all properties that were supplied as part of the JSON, including nested properties. However, if I do myobject.GetType().GetProperties() it only returns properties of Newtonsoft.Json.Linq.JContainer instead of the properties I'm looking for (that were part of the JSON).
Any idea how to do this?
I think this can be a starting point
dynamic dynObj = JsonConvert.DeserializeObject("{a:1,b:2}");
//JContainer is the base class
var jObj = (JObject)dynObj;
foreach (JToken token in jObj.Children())
{
if (token is JProperty)
{
var prop = token as JProperty;
Console.WriteLine("{0}={1}", prop.Name, prop.Value);
}
}
EDIT
this also may help you
var dict = JsonConvert.DeserializeObject<Dictionary<string, object>>(jObj.ToString());
Related
I'm trying to debug my JProperty object but somehow I can not get all the data out of this object. When I debug te JProperty it says it has the data im trying to recieve but I'm only able to obtain a part of it, explanation:
So my response JSON looks like this:
{"url":"www.microsoft0nline.nl\/test.php","time":"2019-06-19 09:50:49","stringvalue":"otherValue1","intvalue":433,"array":["35","37","43"],"otherObject1":{"name":"object1","description":"A object type","size":120}}
I'm iterating through this with the following code:
foreach (JProperty property in jsonResponse.Properties())
{
}
So when I run my code in debug mode and i debug these properties I'm getting the following:
As you all can see the parent of property has the object "otherObject1" within.
Now I iterate through this property with the following code:
foreach (var itemsOfResponse in property)
{
var dataJson = itemsOfResponse;
System.Diagnostics.Debug.WriteLine(dataJson);
}
And the response in my debugger looks like this:
www.microsoft0nline.nl/test.php
2019-06-19 10:01:49
otherValue1
433
[
"35",
"37",
"43"
]
The response contains all the values of my json response exept the one of "otherObject1", how is this possible? And is there a way to obtain the key values(url, stringvalue, intvalue, etc) of these properties to?
Hope someone can help me out here!
JProperty is only a single name value token pair.
JObject will contain many JToken objects (including JProperty and JObject instances).
For what you are trying to do, you should probably use JToken as both JProperty and JObject are JToken derived classes.
Normally I'm using Newtonsoft to deserialize like this
List<myObject> deserializeObj = JsonConvert.DeserializeObject<List<myObject>>(mysample);
But now, i'm facing a problem where the attribute of mysample can be dynamic which is user define themselves. Thus i cannot use myObject anymore as it is fixed class. So how can i deserialize object like that?
For example the mysample can be something like bellow and etc:
[{"Name":"a","Phone":"a","Ic":"a"},{"Name":"b","Phone":"b","Ic":"b"}]
OR
[{"Id":"a"},{"Id":"b"}]
Target Framework is .NET Framework 3.5
you can use Dynamic Type
List<dynamic> deserializeObj = JsonConvert.DeserializeObject<List<dynamic>>(mysample);
.NET Framework 3.5 :
List<object> deserializeObj = JsonConvert.DeserializeObject<List<object>>(mysample);
well you can then use reflection to access value
sample:
System.Reflection.PropertyInfo pi = item.GetType().GetProperty("name");
String name = (String)(pi.GetValue(item, null));
dotnt forget to add using System.Reflection;
To avoid using dynamic, you can parse the json using JArray
JArray array = JArray.Parse(json);
Thus i cannot use myObject anymore as it is fixed class. So how can i deserialize object like that?
To get rid from this problem Newtonsoft.Json have very well feature that we can use
If you don't know which json object or array comes from your resource. means you can't determine its c# respective object then newtonsoft have JObject and JArray can handle this problem like
1) Suppose your json string is object like
var json = #"{ 'Name':'a','Phone':'a','Ic':'a'}";
Then you can use JObject here
JObject jObject = JsonConvert.DeserializeObject<JObject>(json);
2) Suppose your json string is array like
var json1 = #"[{ 'Name':'a','Phone':'a','Ic':'a'},{ 'Name':'b','Phone':'b','Ic':'b'}]";
Then you can use JArray here
JArray jArray = JsonConvert.DeserializeObject<JArray>(json1);
After successfully getting JArray from your json string. you can also querying on your deserialized object to get particular object from it like
JObject jObject1 = jArray.Children<JObject>().FirstOrDefault();
JObject jObject2 = jArray.Children<JObject>().FirstOrDefault(x => x["Name"] != null && x["Name"].ToString() == "a");
int count = jArray.Children<JObject>().Count();
If you want to get certain key:value pair from your json then you can get it by below code
JProperty jProperty = jObject1.Properties().Where(x => x.Name == "Name").FirstOrDefault();
var value = (string)jProperty.Value;
Try once may it help you.
Most of the time we don't, by default, have defined classes in our static language of choice, which presents white a quandary over how to deserialize the e.g. JSON returned from a call to a public and open wen api, dedicated to no single language, except the "language" of e.g. HTML and JSON.
In .NET, these days, nearly all api queries are done with HttpClient, something like the Google Books API ISBN query below:
public class GoogleBooksClient
{
private const string IsbnUrl = "books/v1/volumes?q=isbn:{0}";
private static HttpClient _client = new HttpClient();
...
public async Task<object> GetDetailsByIsbn(string isbn)
{
var json = await _client.GetStringAsync(string.Format(IsbnUrl, isbn));
dynamic objX = JsonConvert.DeserializeObject(json);
return objX;
}
}
The biggest problem here is that whether objX is declared var', object, or dynamic, it is always a reference to a big, ugly JObject instance when DeserializeObject is called without a known type. In this case, the JSON object returned is incredibly complex, and there be dragons waiting for those who endeavour to write a C# class that the said JSON can be parsed into.
This is an ideal, and intended, opportunity for the use of a C# dynamic object, where as the JSON is parsed, properties (and rarely functions for API responses) can be recursively added to the said dynamic object.
Instead, NewtonSoft.JSON tightly binds the data held by the JSON with the heavy red-tape ligature of a quite opaque Jobject data structure. I'm surprised and disappointed that having come so far, NewtonSoft cannot simply extract a pure dynamic object, without all the obfuscating bureaucracy of their JObject maze.
Is there no other way to simply parse the JSON into a C# dynamic object, just like it would be parsed into an explicitly dynamic JavaScript object in other scenarios?
ADDED: By "obfuscating bureaucracy of their JObject maze", I mean the following code:
var json = JsonConvert.SerializeObject(new Person {Id = 196912135012878, Age = 47, Name = "Brady"});
var jObj = JsonConvert.DeserializeObject(json);
produces a JObject instance that my debugger shows as:
This looks, to me, much more like something that should be used internally during parsing of the JSON, and not an end product of that parsing, which should be a pure representation of only the properties parsed from that JSON. That would ideally be a C# dynamic object with no properties for use by any parser.
Rather than a JObject, you can deserialize to an ExpandoObject, which is supported by Json.NET's built-in converter ExpandoObjectConverter. If an array, you can deserialize to a List<ExpandoObject> then select to a List<dynamic>. If a primitive value, you could return JValue.Value.
For instance, if you know in advance your JSON represents an object, just do:
dynamic dyn = JsonConvert.DeserializeObject<ExpandoObject>(json);
If you don't know in advance what the root JSON container might be, you can load it as a JToken and use the following extension method:
public static class JsonExtensions
{
public static dynamic ToDynamic(this JToken token)
{
if (token == null)
return null;
else if (token is JObject)
return token.ToObject<ExpandoObject>();
else if (token is JArray)
return token.ToObject<List<ExpandoObject>>().Cast<dynamic>().ToList();
else if (token is JValue)
return ((JValue)token).Value;
else
// JConstructor, JRaw
throw new JsonSerializationException(string.Format("Token type not implemented: {0}", token));
}
}
Then do:
dynamic dyn = JsonConvert.DeserializeObject<JToken>(json).ToDynamic();
Sample fiddle.
A dynamic object is generated using a Json deserializing component (Jil) I am using, and I am able to access the properties directly. But I don't know their names in advance, so I am trying to get the names with reflection. I tried doing this:
var props = myDynObj.GetType().GetProperties();
but the page times out. Doesn't give me anything in debugger, just sits there doing nothing, or something and not telling me.
This even happens when I even do this:
var t = myDynObj.GetType();
But when I do this, it works:
var val = myDynObj.MyStaticValue1
Just can't really do anything else with it. Anyonw know why, and how I can get this to work?
Please allow me to note:
Before I get started, if you don't know the members already when you're parsing JSON, you should not be parsing into a dynamic object. The built-in .Net JavaScriptConverter class can parse JSON into a IDictionary<string, object> which would be much better for you.
However, if you still want to use dynamic objects for some reason:
If you want to stick with your current library: I dont know how exactly that class is working, and I'm not saying this is the best solution, but by looking at the source it jumps out to me that you can grab a list of the ObjectMembers keys using reflection.
Type t = typeof(JsonObject)
var fi = t.GetField("ObjectMembers", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
IEnumerable<string> keys = ((Dictionary<string, JsonObject>)fi.GetValue(obj)).Keys;
Edit: Seeing that JsonObject implements IDynamicMetaObjectProvider, the following method mentioned in this question will also work on it:
public static IEnumerable<string> GetMemberNames(object target, bool dynamicOnly = false)
{
var tList = new List<string>();
if (!dynamicOnly)
{
tList.AddRange(target.GetType().GetProperties().Select(it => it.Name));
}
var tTarget = target as IDynamicMetaObjectProvider;
if (tTarget !=null)
{
tList.AddRange(tTarget.GetMetaObject(Expression.Constant(tTarget)).GetDynamicMemberNames());
}else
{
if (ComObjectType != null && ComObjectType.IsInstanceOfType(target) && ComBinder.IsAvailable)
{
tList.AddRange(ComBinder.GetDynamicDataMemberNames(target));
}
}
return tList;
}
If you are open to trying a different JSON converter: try this class here: http://pastie.org/private/vhwfvz0pg06zmjqirtlxa I'm not sure where I found it (I can't take credit) but here is an example of how to use it how you want:
// Create dynamic object from JSON string
dynamic obj = DynamicJsonConverter.CreateSerializer().Deserialize("JSON STRING", typeof(object));
// Get json value
string str = obj.someValue;
// Get list of members
IEnumerable<string> members = (IDictionary<string, object>)obj).Keys
Personally I like using the second one, it is simple and easy to use - and builds off of the built in .Net JSON parser.
I'm using the Json.Net library (for .NET v3.5) to handle deserialisation of responses from the EBoss CRM API. As far as I've seen the API documentation is rather spotty, and so I'm having to poke at it myself to see what kind of responses can be elicited.
I wanted to have a single wrapper class EBossApiResponse<T> that would provide properties for any error messages that the API sent back, plus a property containing the deserialised data of type T (which would be restricted to an abstract base class which acts as the underlying type of any classes I created to model the returned data).
My initial poking revealed the first problem. A valid request can return an array of objects, such as: https://ebosscrm.com/api.php/job_type.json
This will easily deserialise to a hypothetical T of List<EBossJobType>. Note that there's no error property in the results.
A malformed request to that same endpoint however returns something different: https://ebosscrm.com/api.php/job_type.json?search[foo]=1
In this case, an array is returned which contains a single object with a single property named message.
(Note, there are calls for which having a parameter named search[something] is valid, but foo is never a valid something)
There is also the possibility for an explicit error to be returned. It looks to me like the API is catching exceptions and formatting a JSON response containing the debug information: https://ebosscrm.com/api.php/candidates.json?uid=114&api_key=f34js3kj
In this case, the returned JSON is not an array, it's a single object. I'm not sure how to cater for these differing response structures. My initial thinking was to have something like:
protected bool IsNonDataResponse(string response)
{
JObject o = JObject.Parse(response);
return o.SelectToken("message") != null || o.SelectToken("error") != null;
}
I could use this method to then either deserialise directly to the right EBossApiResponse<T> type (if true, populating error messages but leaving the .Data property == null), or deserialise to the right List<EBossEntityType>, create a new EBossApiResponse<List<EBossEntityType>>, and set its .Data property.
Then I realised that o.SelectToken("message") won't work, because o would be an array, not an object. Can .SelectToken() take a pattern of the form "[0].message" to get the message property of the first item?
How about this?
JObject o = JObject.Parse(response);
JArray arr = o as JArray;
return (arr != null && (JObject)arr[0].SelectToken("message") != null)
|| o.SelectToken("error") != null;
Or am I barking completely up the wrong tree, and there's a more elegant solution to this whole thing?
You could at least replace JObject.Parse() with JToken.Parse() because JToken is the base class for both JObject and JArray. Then you can check whether the result is either a JArray or a JObject (or maybe a JValue like an integer).
var result = JToken.Parse(response);
if (result is JArray)
{
// ...
}
else if (result is JObject)
{
// ...
}
Have also a look at the documentation for JToken.