2010-11-26 49 views
4

我正在尋找使用UpdateModel方法來在運行時檢索的子類,如果有人可以闡明我是否做它的總散列和/或者我想要做什麼是可能的。MVC的UpdateModel和子類與基類

我正在使用通用操作來控制一堆局部視圖的驗證;我試圖擺脫每個局部視圖的特定操作。

每個局部視圖具有獨特的模式,從基本模型得出:

public class ModelA : ModelBase{ 
    [Required] 
    public string SomeStringProperty{get;set;} 
... 
} 
public class ModelB : ModelBase{ 
    [Required] 
    public DateTime? SomeDateProperty{get;set;} 
... 
} 
public class ModelBase{ 
    public Guid InstanceId{get;set;} 
} 

我使用的行動的FormCollection得到提交的表單元素和它們的值,這包括模型的類型該視圖應該用於驗證其請求。 忽略這對於本例的安全問題,我知道他們的,這是概念

[HttpPost] 
    public ActionResult ChangeCaseState(int id, FormCollection formCollection) 
    { 
     Guid instanceId = new Guid(formCollection["instanceId"]); 
     string modelType = formCollection["modelType"]; 
     //Return a specific Model class based on the event/modelType 
     var args = GetStateModelClass(modelType, instanceId); 

     try 
     { 
      UpdateModel(args); 
      if(Model.IsValid){ 
      ... 
     } 
     catch (Exception) 
     { 
      return View("~/Views/Shared/StateForms/" + modelType + ".ascx", args); 
     }... 

的內部唯一證明這裏是我使用返回基於一個子類的代碼modelType傳遞給控制器​​。

private static ModelBase StateModelClassFactory(string stateModelTypeName, Guid instanceId) 
     { 
      switch (stateModelTypeName) 
      { 
       case "modelTypeA": 
        return new ModelA(workflowInstanceId); 
       case "modelTypeB": 
        return new ModelB(workflowInstanceId); 
    ... 
    } 

由於StateModelClassFactory方法的返回類型是基類的,即使我實際上返回一個子類,通過的UpdateModel方法中使用的模型綁定僅結合對基類中的值。

關於如何解決此問題的任何想法?

UPDATE:

我創建了一個客戶模型綁定:

public class CustomModelBinder : DefaultModelBinder 
    { 
     public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) 
      { 

並指派了新的模型綁定到正確的基類,看看發生了什麼事情引擎蓋下多一點:

ModelBinders.Binders.Add(typeof(ModelBase), new CaseController.CustomModelBinder()); 

當我調試模型聯編程序並檢查bindingContext時,Model屬性表示正確Sub Class,但ModelType屬性是基類的屬性。我應該在更改BindModel方法中的ModelType嗎?如果是這樣的話,關於如何做到這一點的指針,ModelType上的setter似乎已經變得多餘了。我還注意到,子類中的SomeDateProperty實際上是在PropertyMetadata屬性中....看起來如此接近我的行爲。

回答

2

所以我想我已經解決了我的問題。基本上,由於我在調用UpdateModel之前檢索Model類的方式,即使Model是SubClass的Model,它仍然綁定BaseClass - 這是我用於解決特定問題的代碼:

public class SubClassModelBinder : DefaultModelBinder 
{ 
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) 
    { 
     var model = bindingContext.Model; 
     var metaDataType = ModelMetadataProviders.Current.GetMetadataForType(null, model.GetType()); 
     bindingContext.ModelMetadata = metaDataType; 
     bindingContext.ModelMetadata.Model = model; 

     return base.BindModel(controllerContext, bindingContext); 
    } 
} 

而且在Global.asax:

ModelBinders.Binders.Add(typeof(ModelBase), new SubClassModelBinder()); 

感謝達林他inital指針。

+0

+1。感謝您分享您的解決方案。 – 2011-03-09 08:41:16

0

要解決此問題,您可以爲基礎類型編寫一個自定義模型聯編程序,該聯編程序基於字符串屬性的值將返回正確的子實例。

+0

感謝達林,我在我認爲是開始到您的解決方案有一個快速播放和更新的問題。 – Tr1stan 2010-11-26 23:51:14

5

我只是碰到了這個特定的問題,並發現一個更好的一般做法是隻爲了你的模型轉換爲dynamic而傳遞到UpdateModel

[HttpPost] 
public ActionResult ChangeCaseState(int id, FormCollection formCollection) 
{ 
    ...try 
    { 
     UpdateModel((dynamic)args);//!!notice cast to dynamic here 
     if(Model.IsValid){ 
     ... 
    } 
    catch... 

這似乎爲我設置類型的所有可用的屬性,而不管我的變量是否使用基類型。

有一個在CodePlex上提交針對此問題的工作項目:http://aspnet.codeplex.com/workitem/8277?ProjectName=aspnet

+0

謝謝。我正在使用.net 3.5(標籤添加到問題)。我剛剛接觸動態關鍵字,因爲我還沒有在任何.net 4.0網站上工作,如果仍然存在問題,將會嘗試嘗試。 – Tr1stan 2011-07-20 09:42:59