我正在尝试构建一个通用模型绑定器,它使用反射将属性分配给从BindingContext检索的指定类型的对象。所以像这样:
public class ModelBinder : IModelBinder
{
public object BindModel<T, K> (ControllerContext controllerContext, ModelBindingContext bindingContext)
where T : class, new()
where K : class
{
Type ObjectType = typeof(T);
Type InterfaceType = typeof(K);
T obj = new T();
foreach (var Property in ObjectType.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance))
{
Type PropertyType = Property.PropertyType;
// checks if property is a custom data object
if (!(PropertyType.GetGenericArguments().Count() > 0 && PropertyType.GetGenericArguments()[0].GetInterfaces().Contains(InterfaceType)))
{
Property.SetValue(obj, bindingContext.ValueProvider.GetValue(Property.Name), null);
}
}
return obj;
}
显然这不起作用,因为它没有正确实现IModelBinder接口。这样的事情可能吗?
编辑:
为了扩展我为什么这样做,我们的对象使用了很多不同的自定义对象。例如,Class对象:
public class Class : ModelBase<Class>
{
public Class () { }
public virtual string ClassDescription { get; set; }
public virtual string ClassName { get; set; }
public virtual LookUp ClassType { get; set; }
public virtual double Credits { get; set; }
public virtual bool Documents { get; set; }
public virtual LookUp PracticeArea { get; set; }
}
使用LookUp类:
public class LookUp : ModelBase<LookUp>
{
public LookUp () { }
public virtual string DisplayName { get; set; }
public virtual LookUpType Type { get; set; }
}
下拉列表用于LookUps和其他对象,因此我的Class / Create自定义模型绑定器将执行以下操作:
LookUp ClassType = LookUp.Load(long.Parse(bindingContext.ValueProvider.GetValue("ClassType").AttemptedValue))
我不知道如何使用DefaultModelBinder处理这样的事情。
答案 0 :(得分:1)
所以我想出了一个有效的(现在)解决方案。目前它不是很通用,但它适用于我的目的。
public class ModelBinder : DefaultModelBinder
{
public override object BindModel (ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var ModelType = bindingContext.ModelType;
var Instance = Activator.CreateInstance(ModelType);
var Form = bindingContext.ValueProvider;
foreach (var Property in ModelType.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance))
{
Type PropertyType = Property.PropertyType;
// I'm using an ORM so this checks whether or not the property is a
// reference to another object
if (!(PropertyType.GetGenericArguments().Count() > 0 ))
{
// This is the not so generic part. It really just checks whether or
// not it is a custom object. Also the .Load() method is specific
// to the ORM
if (PropertyType.FullName.StartsWith("Objects.Models"))
{
var Load = PropertyType.GetMethod("Load", BindingFlags.Public | BindingFlags.FlattenHierarchy | BindingFlags.Static, null, new Type[] { typeof(long) }, null);
var Value = Load.Invoke(new object(), new object[] { long.Parse(Form.GetValue(Property.Name + ".ID").AttemptedValue) });
Property.SetValue(Instance, Value, null);
}
// checkboxes are weird and require a special case
else if (PropertyType.Equals(typeof(bool)))
{
if (Form.GetValue(Property.Name) == null)
{
Property.SetValue(Instance, false, null);
}
else if (Form.GetValue(Property.Name).Equals("on"))
{
Property.SetValue(Instance, true, null);
}
}
else
{
Property.SetValue(Instance, Convert.ChangeType(bindingContext.ValueProvider.GetValue(Property.Name).AttemptedValue, PropertyType), null);
}
}
}
return Instance;
}
}