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
Related
I have a data that is generated at runtime and stored as a List<dynamic> called "Reports".
"Reports" contains many "Report" which are also generated at run time as a new ExpandoObject().
Each "Report" is assigned various properties (e.g. Report.Name, Report.Value, Report.Order, etc) at runtime before being added to "Reports".
The user is able to select which property they want to view (which are pre-defined).
I want to use LINQ OrderBy to sort "Reports" by the user defined property.
You can cast to IDictionary<string, object> and use square bracket indexers with the property name string, e.g.
dynamic report1 = new ExpandoObject();
report1.Name = "Foo";
dynamic report2 = new ExpandoObject();
report2.Name = "Bar";
var reports = new[] { report1, report2 }.ToList();
var sortBy = "Name";
var first = reports.OrderBy(x => ((IDictionary<string, object>)x)[sortBy]).First();
Console.WriteLine(first.Name); // Bar
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
Say I have this object:
dynamic foo = new ExpandoObject();
foo.bar = "fizz";
foo.bang = "buzz";
How would I remove foo.bang for example?
I don't want to simply set the property's value to null--for my purposes I need to remove it altogether. Also, I realize that I could create a whole new ExpandoObject by drawing kv pairs from the first, but that would be pretty inefficient.
Cast the expando to IDictionary<string, object> and call Remove:
var dict = (IDictionary<string, object>)foo;
dict.Remove("bang");
You can treat the ExpandoObject as an IDictionary<string, object> instead, and then remove it that way:
IDictionary<string, object> map = foo;
map.Remove("Jar");
MSDN Example:
dynamic employee = new ExpandoObject();
employee.Name = "John Smith";
((IDictionary<String, Object>)employee).Remove("Name");
You can cast it as an IDictionary<string,object>, and then use the explicit Remove method.
IDictionary<string,object> temp = foo;
temp.Remove("bang");
Given a dynamic Dapper query such as:
var results = connection.Query<dynamic>("SELECT ....");
I want to remove a couple of the returned columns/properties from the results. The trick is I want to do this without knowing/caring the names of the properties I want to keep, otherwise I would simply project the results into a new anonymous type.
I attempted to loop through the results and cast each to an IDictionary<string, object> so that I could simply remove the key/value pair holding the data. Unfortunately, for whatever reason, the underlying internal FastExpando object doesn't implement the Remove method. The source code for FastExpando shows:
bool IDictionary<string, object>.Remove(string key)
{
throw new NotImplementedException();
}
How can I implement this? To be clear I basically want:
var filteredResults = from r in results
select new { // All properties except a couple of well-known ones }
There was no reason that FastExpandoObject didn't implement those methods, other than: it hadn't needed to. I have now filled in all the missing / NotImplementedException methods. I haven't yet deployed to NuGet, but the code on github/google-code has been updated.
What if you iterate the FastExpandoObject and return a filtered ExpandoObject?
var filteredResults = dynamicResult.Select<dynamic, dynamic>(x =>
{
var filteredRow = new ExpandoObject() as IDictionary<string, Object>;
var props = x as IDictionary<string, object>;
foreach (var prop in props)
{
if (!filter.Contains(prop.Key))
filteredRow.Add(prop);
}
return filteredRow;
});
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.