public class TestContext { // remainder omitted public dynamic ToDynamicObject(object obj, object anonymousTemplate) { var serialized = JsonConvert.SerializeObject(obj); return JsonConvert.DeserializeAnonymousType(serialized, anonymousTemplate); } }Used as
var model = _c.ToDynamicObject(result.Data, new { success = true, data = new SubModel() }); var subModel = ((JObject)model.data).ToObject<SubModel>();I found one solution at http://blog.m0sa.net/2011/02/mvc-unit-testing-jsonresult-actions.html which seemed to improve upon this by using a wrapper class that implements DynamicObject. This got me very close to what I wanted except, again, the nested anonymous objects themselves had to be wrapped individually. Here using my initial implementation of an extension method that used it.
var model = result.Data.AsDynamic(); var cardModel = ((object)model.data).AsDynamic() as SubModel;To fix this I added a bit of code to the wrapper class so that the result of TryGetMember was an anonymous type, it created and returned a DynamicObject wrapper around it. To test if the type was anonymous I used the code found at http://www.liensberger.it/web/blog/?p=191 (referenced from this Stack Overflow question, http://stackoverflow.com/questions/2483023/how-to-test-if-a-type-is-anonymous)
Here’s the final implementation as extensions to object. Note: these are internal to my test project so the restriction to object doesn’t bother me too much. JsonResult.Data has that type and that was the problem I was trying to solve.
internal static class ObjectExtensions { public class DynamicWrapper : DynamicObject { private readonly Type _subjectType; private readonly object _subject; public static dynamic Create(object subject) { return new DynamicWrapper(subject); } private DynamicWrapper(object subject) { _subject = subject; _subjectType = subject.GetType(); } public override bool TryGetMember(GetMemberBinder binder, out object result) { try { var propertyInfo = _subjectType.GetProperty(binder.Name); var getter = propertyInfo.GetGetMethod(); result = getter.Invoke(_subject, null); if (result.IsAnonymous()) { result = Create(result); } return true; } catch { result = null; return false; } } } public static bool IsAnonymous(this object obj) { if (obj == null) { return false; } var type = obj.GetType(); return Attribute.IsDefined(type, typeof(CompilerGeneratedAttribute), false) && type.IsGenericType && type.Name.Contains("AnonymousType") && (type.Name.StartsWith("<>") || type.Name.StartsWith("VB$")) && (type.Attributes & TypeAttributes.NotPublic) == TypeAttributes.NotPublic; } public static dynamic AsDynamic(this object obj) { return DynamicWrapper.Create(obj); } }And the above code sample now becomes much cleaner and I am much happier:
var model = result.Data.AsDynamic();
var subModel = model.data as SubModel;
No comments :
Post a Comment
Comments are moderated.