Open ralfw opened 8 years ago
Just weighing in as a fellow user.
Looks to me like you are correct and this line should be IDynamicMetaObjectProvider instead of DynamicObject.
if (model is DynamicObject) //should be IDynamicMetaObjectProvider right?
{
return GetDynamicMember(model, propertyName);
}
Part of the problem may be from the fact that JObject inherits the interface IDynamicMetaObjectProvider two levels deep in JToken.
public abstract class JToken : IJEnumerable<JToken>, IEnumerable<JToken>,
IEnumerable, IJsonLineInfo, ICloneable, IDynamicMetaObjectProvider
Implements IDynamicMetaObjectProvider
with this implementation:
protected virtual DynamicMetaObject GetMetaObject(Expression parameter)
{
return new DynamicProxyMetaObject<JToken>(parameter, this,
new DynamicProxy<JToken>(), true);
}
and is inherited by
public abstract class JContainer : JToken, IList<JToken>, ICollection<JToken>,
IEnumerable<JToken>, IEnumerable, ITypedList, IBindingList, IList,
ICollection, INotifyCollectionChanged
which is finally inherited by
public class JObject : JContainer, IDictionary<string, JToken>,
ICollection<KeyValuePair<string, JToken>>, IEnumerable<KeyValuePair<string, JToken>>,
IEnumerable, INotifyPropertyChanged, ICustomTypeDescriptor, INotifyPropertyChanging
The documentation on types is abysmal, but the assembly doesn't lie.
However that does show that Nancy should at least attempt resolution (though my guess is that the implementation of JToken won't play nice).
The is
operator doesn't care about inheritance. Json.NET implements IDynamicMetaObjectProvider
correctly.
By the way, looking at the Nancy code I'll speak from my experience of combing reflection with dynamic
: not caching the callsite in GetDynamicMember
will give you garbage performance. You do not want to create it every time.
private static Tuple<bool, object> GetDynamicMember(object obj, string memberName)
{
var binder = Microsoft.CSharp.RuntimeBinder.Binder.GetMember(CSharpBinderFlags.None, memberName, obj.GetType(),
new[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) });
var callsite = CallSite<Func<CallSite, object, object>>.Create(binder);
var result = callsite.Target(callsite, obj);
return result == null ? new Tuple<bool, object>(false, null) : new Tuple<bool, object>(true, result);
}
The SuperSimpleViewEngine is supposed to work with dynamic data implementing
IDynamicMetaObjectProvider
.Here's how I create an object implementing this interface:
The message gets printed, the view model implements the interface.
However, when I pass it to a SuperSimpleViewEngine view (
return View["myview.html", vm]
) it does not get rendered.First I thought, Json.NET does not implement any of the interfaces on its dynamic results. But as is shown above, it does.
Then I checked the source code of the SuperSimpleViewEngine and found this:
This to me means: If a view model implements
IDynamicMetaObjectProvider
then it is not accepted by the view engine.In fact this means, any other interface than
IDictionary<string, object>
is treated the same - except theIDynamicMetaObjectProvider
interface. EspeciallyDynamicDictionaryValue
andDynamicObject
- which get checked - later, will not be treated properly (unless the object also implementsIDynamicMetaObjectProvider
).This looks strange if not wrong.
Could anyone please check?