【问题标题】:MVC model binding - abstract collection propertiesMVC 模型绑定 - 抽象集合属性
【发布时间】:2014-11-28 19:52:36
【问题描述】:

不是重复的,请参阅附加说明

我想绑定如下模型设置

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 绑定集合,但是在发布表单时出现问题,因为它无法创建抽象类 - 即 Shop.Products 中的对象

我查看了子类化 DefaultModelBinder 以覆盖 CreateModel 但是 CreateModel 从未使用参数 modeltype = Product 调用,只有 modeltype = Shop

如何创建一个 ModelBinder 来绑定具有抽象集合作为属性的对象?

澄清
这个问题不是重复的,因为我们不是在处理抽象模型,而是在处理具有抽象对象集合的模型,这在模型绑定系统中经历了一个单独的过程。

【问题讨论】:

标签: c# asp.net asp.net-mvc


【解决方案1】:

已回答,

我遇到的问题是我正在为 Shop 而不是 Products 创建 ModelBinder。

简单。

更新
由于这被否决了,我想我会澄清一下。

我试图模态绑定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】:

澄清一下,对于像我这样偶然发现此页面并寻找解决方案的其他人:

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)

最后,如果您仍然无法获取具体类型的属性,请仔细检查它们实际上是属性,而不是字段!

【讨论】:

    【解决方案3】:

    我认为你应该编写自定义模型 binder。请参阅 How to Bind a collection of Abstract Class or Interface to a Model – ASP.NET MVCMVC 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);
        }
    
    }
    

    【讨论】:

    • 我已经阅读了所有这些。如问题所述,CreateModel 方法不会以modeltype 参数为Product 触发,它只会以Shop 的参数触发
    • 我会澄清一下 - 由于抽象类是模型的属性,因此此方法无济于事,因为它仅用于创建模型 - 而不是所述模型的属性
    猜你喜欢
    • 1970-01-01
    • 2011-04-30
    • 1970-01-01
    • 1970-01-01
    • 2017-04-02
    • 2014-07-21
    • 2012-09-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多