2013-07-22 63 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

如何創建一個模型綁定器將結合具有抽象集合作爲屬性的對象?

澄清
這個問題是不是因爲我們面對的不是一個抽象的模型,我們正在處理有抽象對象的集合的模式重複,這發生在模型綁定系統的獨立進程。

+0

[MVC 3模型綁定子類型(抽象類或接口)]的可能副本(http://stackoverflow.com/questions/9417888/mvc-3-model-binding-a-sub-type-abstract-類或接口) –

+0

不重複。這個問題有一個抽象對象的集合。該問題的解決方案不起作用。 – MrJD

回答

1

回答,

我的問題是,我是創造一個ModelBinder的爲Shop,而不是Products

簡單。

更新
由於這引起了downvoted我想我會澄清。

我試圖模態綁定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())); 
+0

我有類似的情況,具有抽象屬性集合的具體模型,這幫助我得到答案,謝謝! – Sully

0

我認爲你應該寫自定義模型binder.please見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); 
    } 

} 
+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 { ... 

然後在你的模型綁定器,使用這樣的:

string typeName = bindingContext.ValueProvider.GetValue(bindingContext.ModelName + ".type").AttemptedValue; 
Type instantiationType = Type.GetType(typeName); 

從您的EditorTemplate的隱藏字段中獲取類型:

@Html.HiddenFor(m => type) 

最後,如果仍然無法獲得具體類型的屬性,請仔細檢查它們實際上是屬性,而不是字段!