skydrive System.Dynamic.DynamicObject - c#

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 :)

Related

Add two different variable types into a dictionary for multiple custom headers for a GET request

I have the following two headers I need to add to a GET request
string firstHeader = "dksflkjdfjk";
DateTime secondHeader = DateTime.UtcNow;
I then want to add them both to a dictionary but they are different variable types
I have done this so far
Dictionary<string, string> customHeaders = new Dictionary<string, object>();
customHeaders.Add("FirstHeader", firstHeader );
customHeaders.Add("SecondHeader", secondHeader);
But I get an error
CS0029 Cannoth Implicitly convert type 'System.Collections.Generic.Dictionary<string, object>' to 'System.Collections.Generic.Dictionary<string, string>'
My question is how to get the dictionary to accept two different variable types?
Thanks in advance.
You're trying to assign a Dictionary<string, object> to a Dictionary<string, string> which are obviously incompatible types.
Change your code to:
Dictionary<string, object> customHeaders = new Dictionary<string, object>();
or even better:
var customHeaders = new Dictionary<string, object>();
That solves the type casting problem. Furthermore, HTTP Headers are always strings so I am not sure why you want to store different types at all. This is valid for HTTP/2 as well.

How to access the values in a dynamic dictionary in C#?

I have a dictionary which is dynamically generated. In the dictionary, for a single Key, there are multiple values. I am trying to access one of the values in those multiple values. My code so far:
var result = new Dictionary<string, object>();
var dictionary = deserialisedResult as IDictionary<string, object>;
foreach (var item in dictionary)
{
result.Add(item.Key, item.Value);
}
object o = result;
string[] names = o.GetType().GetProperties().Select(p => p.Name).ToArray();
foreach (var prop in names)
{
object propValue = o.GetType().GetProperty(prop).GetValue(o, null);
var value = propValue.GetValue(o,null);
}
But this is not working.
I need to get the values for 'resource'.
When I add watch, I see it nested as such:
Following line is causing issue out here:
string[] names = o.GetType().GetProperties().Select(p => p.Name).ToArray();
GetType() for Object base class type will not yield a Type, which can provide the PropertyInfo[], that you are looking for, even otherwise you are trying to run it for Dictionary<string,object> type, which anyway doesn't have properties to help find the relevant information. For it the Type would always be Dictionary
What you need is fetch the key collection from Dictionary and use them to fetch the values stored in the Dictionary
foreach (var key in result.Keys)
{
var value = result[key];
}
Solution is based on code provided in the question, I am not sure if you have further requirements

ExpandoObject removing multiple values dynamically

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");

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)

Unable to add to a csharp dictionary definition, recieveing "Object Reference Not Set to an instance..."

Hey Guys, I'm trying to add to a dictionary, and recieveing the "Object reference not set to an instance of an object." error. Which I think means that what I'm trying to set it to doesn't exist?
This is the relevant code:
Dictionary<string, Dictionary<int, Dictionary<string, string>>> user = new Dictionary<string, Dictionary<int, Dictionary<string, string>>>();
user.Add("approved", null);
user.Add("pending", null);
user.Add("declined", null);
int zz = 0;
while (results.Read())
{
Dictionary<string, string> field = new Dictionary<string, string>();
for (int i = 0; i < results.FieldCount; i++)
{
switch (fds[i].ToString())
{
case "gender":
string gend = ((Convert.ToBoolean(results[i])) == false) ? "Male" : "Female";
field.Add("gender", gend);
break;
default:
field.Add(fds[i], results[i].ToString());
break;
}
}
string status = results[0].ToString();
user["approved"].Add(zz, field);
zz++;
}
Is there an issue with the way I am setting the three dictionaries at the beginning?
Thanks,
Psy
You have a third level in your nested dictionary structure, and you're skipping initialization of the second level. At the very least, you need to add:
user["approved"] = new Dictionary<int, Dictionary<string, string>>();
What would probably be better, is to do initialization further up front:
user.Add("approved", new Dictionary<int, Dictionary<string, string>>());
user.Add("pending", new Dictionary<int, Dictionary<string, string>>());
user.Add("declined", new Dictionary<int, Dictionary<string, string>>());
Personally, I wouldn't use a Dictionary for user at all. It implies that there are a variable number of statuses of a request (or whatever), while in fact there is a finite amount of possibilities: pending, approved, declined. In my opinion, you would be better off writing a class that holds 3 collections for that.
This also helps in that you wouldn't have three nested Dictionaries, making the code more readable. It was enough to confuse you, let alone someone maintaining the code after you :)
You never create a Dictionary<int, Dictionary<string, string>> object, so in the line of code:
user["approved"].Add(zz, field); // user["approved"] is null
user is a dictionary mapping strings to a dictionary (the details of which aren't important for our purposes). The line
user.Add("approved", null);
adds an entry to user mapping "approved" to the null dictionary. You never set the dictionary that "approved" is mapped to a non-null dictionary so that when you hit the line
user["approved"].Add(zz, field);
you are trying to invoke the method Dictionary.Add on a null dictionary. You can fix this by adding the line
user["approved"] = new Dictionary<int, Dictionary<string, string>>();
The same applies to the other two entries in user.
What about:
user["approved"] = field;
The line:
user["approved"].Add(zz, field);
bangs with a NullReferenceException because when you access user["approved"] it returns null because it's not initialized.

Categories