不重复,请参阅附加说明
我想绑定一个模型设置,如下所示
public class Shop{
public string Name {get;set;}
public ICollection<Product> Products {get;set;} //Product is abstract
}
public abstract class Product{
public string Name {get;set;}
}
public class ProductA : Product{
public string foo {get;set;}
}
public class ProductB :Product{
public string bar {get;set;}
}
像这样的控制器
public ActionResult(){
Shop model = ShopFactory.GetShop();
return View(model);
}
[HttpPost]
public ActionResult(Shop model){
//....
}
我正在使用BeginCollectionItem绑定集合,但是在POST表单时会出现问题,因为它无法创建抽象类 - 即Shop.Products中的对象
我已经考虑将DefaultModelBinder
子类化为覆盖CreateModel
但是从不使用参数modeltype = Product
调用CreateModel,只调用modeltype = Shop
如何创建一个ModelBinder,它将一个具有抽象集合的对象绑定为属性?
澄清
这个问题不是重复的,因为我们没有处理抽象模型,我们正在处理一个具有抽象对象集合的模型,这在模型绑定系统中经历了一个单独的过程。
答案 0 :(得分:3)
只是为了澄清,对于像我这样偶然发现这个页面寻找解决方案的人:
MVC 3 Model Binding a Sub Type (Abstract Class or Interface) 正好您正在寻找什么。 由于BeginCollectionItem,您无需执行任何特殊操作。
只需为您收集的任何抽象类编写模型绑定器,并使用以下内容装饰抽象类:
[ModelBinder(typeof(MyModelBinder))]
public abstract class MyClass { ...
然后在你的ModelBinder中,使用以下内容:
string typeName = bindingContext.ValueProvider.GetValue(bindingContext.ModelName + ".type").AttemptedValue;
Type instantiationType = Type.GetType(typeName);
从EditorTemplate的隐藏字段中获取类型:
@Html.HiddenFor(m => type)
最后,如果你仍然无法获得具体类型的属性,请仔细检查它们实际上是属性,而不是字段!
答案 1 :(得分:1)
回答,
我遇到的问题是我正在为Shop
创建一个ModelBinder,而不是Products
。
简单。
<强>更新强>
由于这被低估了,我以为我会澄清。
我试图模态绑定Shop
类,因为那是我发送给视图的类。在我的脑海里,这是有道理的,因为这是我所约束的模型。问题是DefaultModelBinder中的一个方法在遇到IEnumerable
中的任何复杂对象时调用了CreateModel。所以解决方案是继承DefaultModelBinder
public class ProductModelBinder : DefaultModelBinder{
protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
{
if (modelType.Equals(typeof(Product)))
{
//For now only support Product1's
// Todo: Add support for different types
Type instantiationType = typeof(Product1);
var obj = Activator.CreateInstance(instantiationType);
bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, instantiationType);
bindingContext.ModelMetadata.Model = obj;
return obj;
}
return base.CreateModel(controllerContext, bindingContext, modelType);
}
并将所述子类注册到绑定器:
ModelBinders.Binders.Add(new KeyValuePair<Type, IModelBinder>(typeof(FormItem), new Forms.Mvc.FormItemModelBinder()));
答案 2 :(得分:0)
我认为您应该编写自定义模型binder.please请参阅How to Bind a collection of Abstract Class or Interface to a Model – ASP.NET MVC和MVC 3 Model Binding a Sub Type (Abstract Class or Interface)。
public class MyModelBinder : DefaultModelBinder
{
protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
{
/// MyBaseClass and MyDerievedClass are hardcoded.
/// We can use reflection to read the assembly and get concrete types of any base type
if (modelType.Equals(typeof(MyBaseClass)))
{
Type instantiationType = typeof(MyDerievedClass);
var obj=Activator.CreateInstance(instantiationType);
bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, instantiationType);
bindingContext.ModelMetadata.Model = obj;
return obj;
}
return base.CreateModel(controllerContext, bindingContext, modelType);
}
}