2013-07-22 5 views
2

Не дубликат см прилагается пояснениеMVC модель привязки - абстрактные свойства коллекции

Я хотел бы связать установку модели вроде следующего

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, который будет связывать объект, который имеет абстрактную коллекцию как свойство?

Разъяснение
Этот вопрос не является дубликатом, потому что мы имеем дело не с абстрактной модели, мы имеем дело с моделью, которая имеет коллекцию абстрактных объектов, это проходит отдельный процесс в системе обязательного модели.

+0

Возможный дубликат [MVC 3 Model Binding a Sub Type (абстрактный класс или интерфейс)] (http://stackoverflow.com/questions/9417888/mvc-3-model-binding-a-sub-type-abstract- class-or-interface) –

+0

Не дубликат. Этот вопрос имеет набор абстрактных объектов. Решение в этом вопросе не работает. – MrJD

ответ

1

Ответил,

Проблема у меня было, что я создавал ModelBinder для Shop вместо Products.

Простой.

Update
Так как это был downvoted я думал, что уточнить.

Я пытался связать класс Shop, потому что это был класс, который я отправлял на просмотр. В моей голове это имело смысл, потому что это была модель, к которой я привязывался. Проблема заключалась в том, что метод в DefaultModelBinder назывался CreateModel, когда он сталкивался с любым сложным объектом в IEnumerable. Таким образом, решение было подкласс 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())); 
+0

У меня был похожий сценарий, конкретная модель с набором абстрактных свойств, это помогло мне получить ответ, спасибо! – Sully

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); 
    } 

} 
+0

Я уже все прочитал. Как указано в вопросе, метод CreateModel не запускается с аргументом 'modeltype' как' Product', он только когда-либо запускается с аргументом как 'Shop' – MrJD

+0

. Я уточню это - поскольку абстрактный класс является свойством модель этот метод не поможет, поскольку он предназначен только для создания модели - не свойства указанной модели – MrJD

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); 

чтобы получить тип из скрытого поля в редактореTemplate:

@Html.HiddenFor(m => type) 

Наконец, если вы все еще не можете получить свойства ваших конкретных типов, дважды проверьте, что они на самом деле являются свойствами, а не полями!

Смежные вопросы