2

Given an System.Object, how do I get a dynamic object with which to access any members it might have.

Specifically, I want to unit test an ASP.NET MVC 3 controller action which returns a JsonResult. The JsonResult has a Data property of type object. I'm populating this object with an anonymous type:

return Json(new { Success = "Success" });

In my test, I want to do something like

var result = controller.Foo();

Assert.That(((SomeDynamicType)result.Data).Success, Is.EqualTo("Success"));

How is this done?

UPDATE
Though result.Data is of type object, inspecting it in the Watch window shows it has the following type:

{
    Name = "<>f__AnonymousType6`1" 
    FullName = "<>f__AnonymousType6`1[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]"
} 
System.Type {System.RuntimeType}
Greg B
  • 14,597
  • 18
  • 87
  • 141
  • What is the type of `result.Data`? Is it `new {...}` or the `Json` object or a `string` or...? *It should work assuming result.Data is what is expected*, here is a LINQPad example that does work: `var x = new { X = 1 }; var y = (dynamic)x; ((object)y.X).Dump();`. –  Aug 31 '11 at 21:48
  • @pst, `result.Data` is typed as `object` but it is populated by the `new {Success = "Success"}` being passed into the `return Json(...)` call. – Greg B Aug 31 '11 at 21:51
  • Can see how the `JsonResult` is created? I see a `Json` wrapping the `new {}`... (what is the full `Json` type used?) Try to break on the exception and view the data/type info of the object in Data. Compare the `new {...}` object (by reference as well) and the object in Data. –  Aug 31 '11 at 21:54
  • Have a look at the discussion at http://stackoverflow.com/questions/2634858/how-do-i-reflect-over-the-members-of-dynamic-object – Eddy Aug 31 '11 at 22:10

3 Answers3

3

Anonymous types are internal, and the dynamic api's are called by the compiler in such a way to respect that protection. Using ImpromptuInterface, open source available in nuget, it has an ImpromptuGet class that will allow you to wrap your anonymous type and will use the dynamic api's as if from the anonymous type itself so you don't have the protection issue.

//using ImpromptuInterface.Dynamic
Assert.That(ImpromptuGet.Create(result.Data).Success, Is.EqualTo("Success"));
jbtule
  • 31,383
  • 12
  • 95
  • 128
1

You can use an implementation of DynamicObject:

public class MyDynamic: DynamicObject
{
    private readonly Dictionary<string, object> dictionary = new Dictionary<string, object>();

    public MyDynamic(object initialData)
    {
        if (initialData == null) throw new ArgumentNullException("initialData");
        var type = initialData.GetType();
        foreach (var propertyInfo in type.GetProperties())
        {
            dictionary.Add(propertyInfo.Name, propertyInfo.GetValue(initialData, null));
        }
    }

    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        dictionary.TryGetValue(binder.Name, out result);
        return true;
    }

    public override bool TrySetMember(SetMemberBinder binder, object value)
    {
        dictionary[binder.Name] = value;
        return true;
    }

}

and then:

    public void MyTest()
    {
        var json = new {Success = "Ok"};
        dynamic dynObj = new MyDynamic(json);
        Assert.AreEqual(dynObj.Success, "Ok");
    }
Charlie
  • 1,265
  • 15
  • 18
-1

Since you are trying to inspect an object which is Json, why not run result.Data through JsonValueProviderFactory, and then search the backing store for the key named "Success"?

counsellorben
  • 10,924
  • 3
  • 40
  • 38