ExpandoObject removing multiple values dynamically - c#

Originally I deserialize a JSON string into a dynamic type List, this worked fine until moving it to the server at which point the dynamic list stopped working. The only answer I could find is that this is not abnormal behavior for lists. The original question
So from that I changed my dynamic list to an ExpandoObject
dynamic root = JsonConvert.DeserializeObject<ExpandoObject>(jsonstring, new ExpandoObjectConverter());
Originally in my dynamic list I called
root.record.form_values.Remove("f161");
root.record.form_values.Remove("41df");
root.record.form_values.Remove("a228");
root.record.Remove("changeset_id");
Which worked as expected removing those objects from the List which I eventually turn back into JSON and send it back to an API.
After doing some reading on ExpandoObjects I found that to delete you need to throw it out to a IDictionary in order to have the .Remove functionality.
So I did this:
dynamic dict = (IDictionary<string, object>)root;
And then replaced my code with:
dict.record.form_values.Remove("f161");
dict.record.form_values.Remove("41df");
dict.record.form_values.Remove("a228");
dict.record.Remove("changeset_id");
This resulted in the error
'System.Dynamic.ExpandoObject' does not contain a definition for
'Remove'
So after a bit more reading I tried the following:
dict = (IDictionary<string, object>)root.record.form_values.Remove("f161");
dict = (IDictionary<string, object>)root.record.form_values.Remove("41df");
dict = (IDictionary<string, object>)root.record.form_values.Remove("a228");
dict = (IDictionary<string, object>)root.record.Remove("changeset_id");
Which resulted in the same error...
If anyone can give me a clue on where to go to from now, that would be great.
FYI The JSON Structure looks as such:
"{
\"record\":{
\"status\":\"somevalue\",
\"form_values\":
{
\"833b\":\"somevalue\",
\"683b\":\"somevalue\",
\"c9ca\":{\"other_values\":[],\"choice_values\":[\"somevalue\"]}
},
\"latitude\":somevalue,
\"longitude\":somevalue
}
}"
The original code with the DynamicList (Which worked) looks as such:
string jsonstring = data;
var root = Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(jsonstring);
root.record.assigned_to = assignedto;
root.record.assigned_to_id = assignedtoid;
root.record.status = status.ToString();
root.record.bb42 = abudgetunit;
root.record.f694 = abudgetunitstr;
root.record.form_values.Remove("f161");
root.record.form_values.Remove("41df");
root.record.form_values.Remove("a228");
root.record.Remove("changeset_id");

You're very close. There are nested expando objects in the structure, and you've only converted the first one. If you find the nested objects and convert all the way down to the form_values then it will work.
dynamic root = JsonConvert.DeserializeObject<ExpandoObject>(jsonstring, new ExpandoObjectConverter());
var rootDict =(IDictionary<string, object>) root;
var recordDict = (IDictionary<string, object>) rootDict["record"];
var formValuesDict = (IDictionary<string, object>) recordDict ["form_values"];
formValuesDict.Remove("683b");

Related

Getting access to ArrayList object

I'm developing an application that reads some JSON data and makes some statistics, but now I've run into a problem.
I have a string like this:
{
"position":[
{
"someKey1":"someVal1",
"someKey2":"someVal2",
},
{
"someKey1":"someVal3",
"someKey2":"someVal4",
}
}
I want to access the someKeys and someValues.
I'm converting it to a dictionary like this:
Dictionary<string, object> values = deserializeJSON(json_string);
Edit 1: Sorry, forgot to add deserializeJSON:
private Dictionary<string, object> deserializeJSON(string p_jsonObject)
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
return serializer.Deserialize<Dictionary<string, dynamic>>(p_jsonObject);
}
Now I have trouble getting access to the list of values with the key "position". If I try to print the type of values["position"] I get:
System.Collections.ArrayList
So I thought I could just iterate through this, but I can't. I tried using enumerator (read in here that it would make it possible to iterate over the objects, and that I have to add it to an ArrayList to cast it):
ArrayList arr = new ArrayList();
IEnumerable enumerable = values["position"] as IEnumerable;
foreach (object element in enumerable)
{
arr.Add(element);
}
When I print arr[0] I get:
System.Collections.Generic.Dictionary`2[System.String,System.Object]
Here I'm confused. I assume it's the list of someKeys and someVals, which should be correct, right?
Now I've tried, with no luck, getting access to these values. I tried arr[0]["someKey1"] but get an error that I cannot apply indexing to 'object'.
Any ideas on a solution? Ideally a more elegant solution? :)
Thanks in advance
You can use Linq to JSON (add Newtonsoft's JSON.NET from NuGet):
JObject jo = JObject.Parse(json);
var value = (string)jo["position"][1]["someKey1"]; // someVal3
Another sample:
JObject jo = JObject.Parse(json);
JArray positions = (JArray)jo["position"];
foreach (var item in positions)
{
// use (string)item["someKey1"]
// use (string)item["someKey2"]
}
You can access the elements as follows:
var enumerable = (IEnumerable)values["position"]; // Will get you the enumerable ArrayList
(Dictionary<string,object>)values["position"][0]; // Will get you the First element of the ArrayList
(string)values["position"][0]["someKey1"]; // Will get you someKey1 from the first position of position

how to convert dictionary into object and save via sql database

In c# language using dictionary to store and that dictionary converted to object at finally that object stored to SQL server..
You could serialize it and save it as a json string. You could use http://nuget.org/packages/newtonsoft.json to serialize and deserialize you dictionary.
If you really want to convert the dictionary to an object that has the items of the dictionary as properties, you can use ExpandoObject:
var dict = new Dictionary<string, object> { { "Property", "foo" } };
var eo = new ExpandoObject();
var eoColl = (ICollection<KeyValuePair<string, object>>)eo;
foreach (var kvp in dict)
{
eoColl.Add(kvp);
}
dynamic eoDynamic = eo;
string value = eoDynamic.Property;
But I'm not sure how is doing that going to help you

skydrive System.Dynamic.DynamicObject

I'm trying to get a listing of all the folders for a signed in user on SkyDrive.
LiveOperationResult operationResult = await client.GetAsync("me/skydrive/files");
dynamic result = operationResult.Result;
I'd like to be able to do something like this:
Dictionary<string, object> folderData = (Dictionary<string, object>)result;
List<object> folders = (List<object>)folderData["data"];
foreach (object item in folders)
{
Dictionary<string, object> folder = (Dictionary<string, object>)item;
if (folder["name"].ToString() == "Folder Name")
{
showToastMessage(folder["id"].ToString());
return;
}
}
However, on this line:
Dictionary<string, object> folderData = (Dictionary<string, object>)result;
I'm getting an error:
Cannot convert type 'System.Dynamic.DynamicObject' to
'System.Collections.Generic.Dictionary'
Does anyone have any idea how I can do get around this issue?
The problem is that LiveOperationResult.Result isn't necessarily guaranteed to be a Dictionary<string, object>. It is however defined as an IDictionary<string, object>.
Mind you, you don't appear to even need to cast the Result property to a dictionary of any sort; you should be able to use the dynamic variable to directly access the list you want to iterate.
List<object> folders = (List<object>)result.data;
I think that you receive this because you have declared result using the following code
dynamic result = operationResult.Result;
this will declare result as a new System.Dynamic.DynamicObject so that, when we say
Dictionary<string, object> folderData = (Dictionary<string, object>)result;
You are trying to convert result of type System.Dynamic.DynamicObject to System.Collections.Generic.Dictionary which is not possible and that's why you receive the error.
Thanks,
I hope you find this helpful :)

Convert KeyValuePair to anonymous type in a LINQ query

I have an IEnumerable<KeyValuePair<string,string>>, from which I would like, ideally, an anonymous object which has the keys as property names and the values as property values.
I've tried various selection expressions (none of which even compiled...) and an approach using ExpandoObject (see below), but without success. Is there a good way to do this? If possible, I'd like to avoid an extra explicit iteration over the collection (i.e. do it all with a LINQ statement of some sort).
This is what I've tried so far. I hope it also clarifies what I'm trying to do:
var kvps = getProps(); // returns IEnumerable<KeyValuePair<string,string>>
dynamic o = new ExpandoObject();
foreach (var kvp in kvps)
{
o.Add(kvp);
}
This is OK at compile time, but at runtime I get a YSOD stating 'System.Dynamic.ExpandoObject' does not contain a definition for 'Add' - I guess it works at compile time because o is dynamic, so the compiler can't know if a method .Add() has been added to it since it was instantiated. The odd thing is, that on the MSDN documenation page for ExpandoObject .Add() is listed as one of several "explicitly implemented interface methods".
It is not necessary for me to get this into a dynamic object - I just need to get something that has property names and values according to the keys and values of the key-value pairs.
Update: Well, this is embarrassing. Turns out this was something of an XY-problem too.
I'm trying to render this to JSON using the built-in features of ASP.NET MVC, by simply returning Json(data) in my controller. The answers all worked very well to do what I first asked, but when I pass this object as data I still don't get what I want:
// What I get:
[
{ Key: 'firstkey', Value: 'FirstValue' },
{ Key: 'secondKey', Value: 'secondValue' }
]
// What I want:
{ firstKey: 'FirstValue', secondKey: 'secondValue' }
Apparently, an ExpandoObject with the relevant properties added didn't cut it - it was cast to a dictionary before rendering...
You need to use the ExpandoObject as an IDictionary<string, object> while populating it:
var kvps = getProps(); // returns IEnumerable<KeyValuePair<string,string>>
IDictionary<string, object> o = new ExpandoObject();
foreach (var kvp in kvps)
{
// Or use Add(kvp.Key, kvp.Value), if you want
o[kvp.Key] = kvp.Value;
}
dynamic d = o;
// Now you can use the properties
ExpandoObject explicitly implements IDictionary<string, object> - so you need to cast it to one first:
var kvps = getProps();
dynamic o = new ExpandoObject();
var dict = o as IDictionary<string, object>;
foreach (var kvp in kvps)
{
dict.Add(kvp.Key, kvp.Value);
}
Now you can use o as you would expect:
var example = o.YourKey;
I'm trying to render this to JSON using the built-in features of ASP.NET MVC, by simply returning Json(data) in my controller.
Interesting.
To do that, you serialize a dictionary, not an ExpandoObject. MVC 3's JSON serializer already does that with a dictionary. All you have to do is convert your IEnumerable<KeyValuePair<string, object>> to a dictionary:
var kvps = getProps();
var dictionary = kvps.ToDictionary(k => k.Key, v => v.Value);
return Json(dictionary, JsonRequestBehavior.AllowGet); //take out allow get if you don't need it.
No dynamics required.
I think you have to cast your expando object to IDictionary and call Add(string, object)

Dynamic query with linq to IDictionary<string, object>?

This question is similar to this question but not quite the same.
Can I make a dynamic query on a linq-to-sql data context and have the result return as an IDictionary<string, object> where the key is the name of the column?
A bit like so (doesn't compile, but illustrates the intention)
IDictionary<string, object> data = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
data = db.ExecuteQuery<IDictionary<string, object>(queryString, params).ToDictionary(
k=>nameOfColumn,
k=>k
)
Obviously I'm totally off the map in the data = db.ExecuteQuery...
I have the feeling that the executeQuery is not what I'm ought to use as this one already tries to do the mapping to an object. For this particular use case I don't want that.
You'll need to include an object type to materialize; how about:
var data = db.ExecuteQuery<SomeType>(queryString, params)
.ToDictionary(st => st.SomeKey);

Categories