I have a function that returns an anonymous type which I want to test in my MVC controller.
public JsonResult Foo()
{
var data = new
{
You can use NewtonSoft or the Asp.net MVC libraries:
var data = Json.Decode(Json.Encode(_controller.Foo().Data));
var data=JsonConvert.DeserializeObject<Dictionary<string,object>>(JsonConvert.SerializeObject((_controller.Foo().Data))
Anonymous type is a regular static type in .NET, it's just that you do not give it a name (a compiler, however, does). That's why casting it to dynamic
will not work. However, if you have control over Foo()
, you can construct and return a dynamic
object instead of anonymous, and then your code is going to work. This should do the trick:
dynamic JsonResult Foo() {
dynamic data = new ExpandoObject();
data.details = "something";
data.mode = "More";
return Json(data);
}
Anonymous objects are internal
, which means their members are very restricted outside of the assembly that declares them. dynamic
respects accessibility, so pretends not to be able to see those members. If the call-site was in the same assembly, I expect it would work.
Your reflection code respects the member accessibility, but bypasses the type's accessibility - hence it works.
In short: no.
As suggested by @TrueWill and @Marc Gravell, who also referred to this blog post
Since this is for unit testing, you could use InternalsVisibleTo. See Anonymous Types are Internal, C# 4.0 Dynamic Beware! Thanks to @MarcGravell for pointing out that anonymous objects are internal!
Bottom line: Set up an [assembly: InternalsVisibleTo("foo")]
mapping if you want to share an anonymous object from one assembly to another. In the OP case, it would be a matter of setting this in the MVC controller project, referring to the test project. In my specific case, the other way around (since I'm passing an anonymous object from my test project into the "production code" project).
The easiest way in that "other project" to be able to use it is definitely to cast it to dynamic
and then just use the properties like normal. It does work, no problems whatsoever.
So, bottom line: I feel that Marc Gravell's answer is slightly incorrect; this can clearly be done
(iff the projects in question are modifiable by you, so you can set up the InternalsVisibleTo mapping accordingly, and this does not pose a problem for whatever other reason).
This blog had a working answer: http://blog.jorgef.net/2011/06/converting-any-object-to-dynamic.html - Thanks @Jorge-Fioranelli.
public static class DynamicExtensions {
public static dynamic ToDynamic(this object value) {
IDictionary<string, object> expando = new ExpandoObject();
foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(value.GetType()))
expando.Add(property.Name, property.GetValue(value));
return expando as ExpandoObject;
}
}