dynamic data = JsonConvert.DeserializeObject(result);
foreach (var field in data)
{
var deserializedData = new DeserializedData
{
Label = field.Key.ToObject<string>(),
Content = field.Value.ToObject<string>()
};
}
Note: data = {"name":"test"}
Error:'Newtonsoft.Json.Linq.JProperty' does not contain a definition for 'Key'
I think I understand what the issue is but I am not sure if there is a way to achieve this behavior or is there a different approach to handle the dynamic key value scenarios like this.
The Key will change so I don't know if its going to be name or phone or email or some other field...
In order to iterate through the children of the returned data as an IEnumerable<KeyValuePair<string, JToken>>, you need to explicitly declare the deserialized object as a JObject:
var data = JObject.Parse(result);
foreach (var field in data)
{
var deserializedData = new DeserializedData
{
Label = field.Key,
Content = field.Value.ToObject<string>()
};
}
When you do dynamic data = JsonConvert.DeserializeObject(result);, the foreach ends up calling the IEnumerable<JToken> iterator in the base class JToken. I.e. the following also works:
dynamic data = JsonConvert.DeserializeObject(result);
foreach (var field in data)
{
// "field" happens to be of type JProperty
var deserializedData = new DeserializedData
{
Label = field.Name,
Content = field.Value.ToObject<string>()
};
}
Though I prefer the strongly typed version using JObject since more checking can be done at compile time.
According to the documentation the JProperty's value contains the key, and the JProperty's children are the values. source
Related
I have the following code, where page.Fields is an ExpandoObject. I'm iterating through some user-defined properties and adding them to an Expando, cast to an IDictionary<string,string> to allow me to add new field name / values dynamically, but when I set the Fields property to the value of props, serializing afterwards only gives names with blank values of {}. Why?
page.Fields.Foo = "asdf";
var test = JsonConvert.SerializeObject(page); // shows Foo=asdf in the json
// attach all fields to the page object, casting to an IDictionary to be able to add var names
var props = new ExpandoObject() as IDictionary<string, Object>;
foreach (string key in Request.Form.Keys)
{
if (key.StartsWith("Fields."))
{
var fieldName = key.Substring(key.IndexOf(".") + 1);
props.Add(fieldName, Request.Form[key]);
}
}
var test2 = JsonConvert.SerializeObject(props); // blank values of {}
page.Fields = props as ExpandoObject;
// loses the values for the Fields property
test = JsonConvert.SerializeObject(page);
UPDATE the curse of Nancy strikes, the Request.Form values turned out to be dynamic, so I had to .ToString() it to make it fit into the expected IDictionary<string,string>
To correctly serialize the data you must declare the variable as dynamic, not as an ExpandoObject, JSON .net uses reflection to retrieve properties, if it's a dynamic it casts it as an ExpandoObject and uses the keys as property names, but if you pass the ExpandoObject directly it tries to retrieve the properties from the ExpandoObject type.
Just change
var props = new ExpandoObject() as IDictionary<string, Object>;
to
var props = new ExpandoObject();
var iProps = props as IDictionary<string, Object>;
Use iProps to add the data and pass props to the serialization.
EDIT:
You're storing the value in "Page.Fields", this must be dynamic also.
I'm suspect it's a defect and you are not getting anything for Request.Form.Keys that's matches Field. criteria.
your code works fine for me if I've a page class with dynamic Fields property
I need to cast JArray which I received from browser to list of MyType object. The problem is that I don't want to use .ToObject<> extension because object sended from browser can have missing or extra values and I cannot change deserializer. I wrote my own parser to receive data from single JObject. Usage:
foreach (var _object in _jarray)
{
using (var tp = new TokenParser(_object))
{
MyType test = new MyType()
{
id = tp.ConvertToInt("token_key")
};
}
}
What I want to do is something like this
_jarray.ForEach(_object => {
using (var tp = new TokenParser(_object))
{
MyType test = new MyType()
{
id = tp.ConvertToInt("token_key")
};
}
});
I don't want to cast elements like:
_jarray.Select(x =>
(int)["token_key"]
);
I tried to wrote this extension based on LINQ equivalent of foreach for IEnumerable<T> but it seems that Action requires T as parameter type. I don't need this because JArray is an array of JObject.
Is this possible to achieve?
I have a problem in creating dynamic objects. Please find the below code,
List<object> membersList = new List<object>();
foreach(var members in activityMembers){
dynamic myObject = new System.Dynamic.ExpandoObject();
myObject.MemberNumber = members.MemberNumber;
myObject.MemberName = members.Name;
foreach (var activity in members.ActivityList)
{
myObject.[activity.ActivityName] = activity.Minutes;
}
membersList.Add(myObject);
}
there inside the second foreach loop, i need to generate the properties to all activities. for example if there are 4 activities in members.ActivityList, then 4 properties needs to be generated for object.
myObject.Activity1 = 10;
myObject.Activity2 = 20;
myObject.Activity3 = 30;
myObject.Activity4 = 40;
How can i do this? What i did wrong here?
Regards,
Karthik.
Remove the . when you are indexing the object i.e. change
myObject.[activity.ActivityName] = activityMinutes;
to
myObject[activity.ActivityName] = activity.Minutes;
Actually this won't solve your problem straight away, it will compile fine but when you attempt to run it will throw a RuntimeBinderException as you can't index into a ExpandoObject directly. You need to cast it as a dictionary before iterating (that's effectively what it is) e.g.
var dict = (IDictionary<string, object>)myObject;
...
dict[activity.ActivityName] = activity.Minutes;
I suspect you need to treat the ExpandoObject as a dictionary for that part:
IDictionary<string, object> dictionary = myObject;
foreach (var activity in members.ActivityList)
{
dictionary[activity.ActivityName] = activity.Minutes;
}
That's the way of assigning properties to an ExpandoObject when you don't know the property name at compile-time.
I have a JSON like this one:
{
"name" : "MyCustomName",
"my_node" : {
"name" : "my_node_name"
},
"dict1":"value1",
"dict2":"value2",
"dict3":"value3",
...
}
and an object:
class Node{
string value;
}
class Sample:IDictionary<string, string>{
Node node;
string name;
}
Node and Name in Sample class are always present.
The thing is I don't know how many "dictN" fields will be... and that's the point.
And the question is:
How to Deserialize that JSON to this Object?
Edit: apparently even with field names harmonized, your deserializer just can't cope with specific fields combined with general dictionary fields.
In which case, I'd just advise deserializing as a Dictionary<string, object> and building with the result:
var d = new JavaScriptSerializer().Deserialize<Dictionary<string, object>>(json);
Sample s = new Sample();
s.name = (string)d["name"];
Node n = new Node();
n.value = (string)((Dictionary<string, object>)d["my_node"])["name"];
foreach (var key in d.Keys.Except(new string[] { "name", "my_node" }))
{
s.Add(key, (string)d[key]);
}
INITIAL IDEA
The following is a dictionary serializer. It has one special case of not accepting empty string.
private void SerializePerinatalModel<T>(IDictionary<string, object> dataModel, T perinatalModel)
{
Type sourceType = typeof(T);
foreach (PropertyInfo propInfo in (sourceType.GetProperties()))
{
if (dataModel.ContainsKey(propInfo.Name))
{
// if an empty string has been returned don't change the value
if (dataModel[propInfo.Name].ToNullSafeString() != String.Empty)
{
try
{
Type localType = propInfo.PropertyType;
localType = Nullable.GetUnderlyingType(localType) ?? localType;
propInfo.SetValue(perinatalModel, Convert.ChangeType(dataModel[propInfo.Name], localType), null);
}
catch (Exception e)
{
// ToDo: log update value errors
}
}
}
}
}
but could be made null safe. It does deal with nullable types.
As JSON is essentially a dictionary type then iterating through the top level types should get you there.
This is written in haste so is only a sketch of an idea.
BETTER IDEA
Also try using
foreach (var item in JsonData.Where(m => m.Key.Substring(0,4) == "dict"))
{
// add item to collection
}
might also do the biz.
You can simply have the output in the form of Dictionary<string, object>, try this piece of code instead.
System.Web.Script.Serialization.JavaScriptSerializer s =
new System.Web.Script.Serialization.JavaScriptSerializer();
var nodes = s.Deserialize<Dictionary<string, object>>(jsonString);
var dictNodes = nodes.Where(w => w.Key.StartsWith("dict"));
Using JavaScript it's possible to access an object using the dot notation or array notation.
var myArray = {e1:"elem1",e2:"elem2",e3:"elem3",e4:"elem4"};
var val1 = myArray["e1"];
var val2 = myArray.e1;
Is it possible to accomplish this using C#?
This is what I have attempted:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(int id, FormCollection frmVals)
{
string value;
Owner owner = new Owner();
foreach (var key in frmVals.AllKeys)
{
value = frmVals[key];
owner[key] = value;
}
}
While there is no way to do this exactly with C#. You could change your code in several ways that may accomplish your goal. First, you could use a Dictionary like this:
var something = new Dictionary<string, object>() {
{ "property", "value"},
{ "property1", 1}
};
foreach (var keyVal in something) {
var property = keyVal.Key;
var propertyValue = keyVal.Value;
}
Another option would be to do it dynamically:
dynamic somethingDyn = new System.Dynamic.ExpandoObject();
somethingDyn.property = "value";
somethingDyn.property1 = 1;
var somethingDynDict = (IDictionary<string, object>)somethingDyn;
var propValue = somethingDyn["property"];
foreach (var keyVal in somethingDynDict) {
var property = keyVal.Key;
var propertyValue = keyVal.Value;
}
If you need to iterate through properties on a strongly typed object you could use reflection:
var owner = new Metis.Domain.User();
var properties = owner.GetType().GetProperties();
foreach (var prop in properties) {
object value = prop.GetValue(owner, null);
}
I wouldn't recommend this, but you could put an indexer in your class, accepting a string, then use reflection to read that property. Something like:
public object this[string key]
{
get
{
var prop = typeof(ThisClassName).GetProperty(key);
if (prop != null)
{
return prop.GetValue(this, null);
}
return null;
}
set
{
var prop = typeof(ThisClassName).GetProperty(key);
if (prop != null)
{
prop.SetValue(this, value, null);
}
}
}
Javascript array notation is not something you can use in C#.
You need to use dot notation to access members of an object.
You will need to access each value directly and assign it:
owner.key = frmVals[key];
owner.key2 = frmVals[key2];
There are workarounds - using dictionaries, dynamic objects or even reflection, but the scenario is not a directly supported by C#.
There is no syntactic equivalent possible in C# but there are some ways to approximate the same feature.
You could mimic the indexer type access using a Dictionary but then you'd lose the property-style access. For property-style access, you could do something similar in C# by using an anonymous type, as in:
var myType = new { e1="elem1",e2="elem2",e3="elem3",e4="elem4"};
var val1 = myType.e1;
However, that doesn't create an array or allow array type access and it doesn't allow for modifications to the type after creation.
To get a closer approximation to the JavaScript feature, you may be able to use ExpandoObject to mimic this a little more closely, or you could implement something yourself.
For that, you'd need a class that has a constructor to auto-generate properties from the passed in array and exposes an indexer, which in turn uses reflection to find the named property.
Initialization of this type would be something like:
var myType = new MyType(new[]{
{"e1", "elem1"},
{"e2", "elem2"},
{"e3", "elem3"},
{"e4", "elem4"}});
This assumes there is a sub-type for each element definition (possibly using Tuple or KeyValuePair. The constructor would then be taking an IEnumerable<T> of that type.
Yes, it's possible.
There are two possibilities:
1) The list of keys and values is dynamic.
The array notation is provided by e.g. System.Collections.Generic.Dictionary<string, blah>
The member access notation can be provided through DLR magic and the dynamic keyword.
2) The list of keys and values is static.
Member access notation is already provided by the C# compiler.
Array notation can be had using Reflection (hopefully with a cache to improve performance).
In the static case, member access notation is MUCH faster. In the dynamic case, array notation will be a little faster.