2015-11-15 21 views
0

我正在開發一個註冊流程,用戶來到並填寫5頁來完成一個過程。我決定有多個視圖和一個控制器以及一個ProcessNext操作方法,以便一步一步地進行。每次Process Next被調用時,它都會獲得原始視圖和下一個視圖。由於每個視圖都與自己的視圖模型相關聯,所以我創建了一個基本視圖模型,這些模型都查看從中派生的特定視圖模型現在的問題是,鑄造拋出異常。這裏是示例代碼ASP.NET MVC投影BaseViewModel到DerivedViewModel

基礎視角模式

public class BaseViewModel 
{ 
    public string viewName; 
} 

個人視圖模型

public class PersonalViewModel : BaseViewModel 
{ 
    public string FirstName; 
    // rest properties comes here 
} 

Index.cshtml

@Model PersonalViewModel 

    @using (Html.BeginForm("ProcessNext", "Wizard", FormMethod.Post, new { class = "form-horizontal", role = "form" })) 
@Html.TextBoxFor(m => m.FirstName, new { @class = "form-control" }) 
<input type="submit" class="btn btn-default" value="Register" /> 

基本上,我在這裏綁定PersonalViewModel的視圖

現在在Controller ProcessNext中,Action方法看起來像這樣。

public ActionResult ProcessNext(BaseViewModel viewModelData) 
{ 
    PersonalViewModel per = (PersonalViewModel) viewModelData; 
} 

這是失敗,拋出一個類型的情況下例外,爲什麼?..

我的想法是隻使用一個動作的方法來改變這一切派生視圖模型,併發送至一個共同的類驗證和處理。請幫我解決這個問題..謝謝!

+0

因爲'viewModelData'不是'PersonalViewModel'您不能將基類型轉換爲派生類型。在任何情況下,這可能無法正常工作,因爲您發回'BaseViewModel'因此與'PersonalViewModel'相關的所有內容都會丟失。 –

+0

在基本的oops ..我很好的情況下派生的基類類型..對嗎?..那麼可以在這裏做什麼來得到這個工作?任何瘋狂的猜測? – user2066540

+0

在第一步,你回發到'public ActionResult Step1(PersonalViewModel模型)'保存數據,然後重定向到一個GET方法,該方法呈現你的'Step2ViewModel'視圖,並返回到'public ActionResult Step2(Step2ViewModel模型)'等在BaseViewModel中沒有任何意義,除了可能包含所有步模型共有的ID屬性 –

回答

0

您看到此例外的原因是您的型號類型爲BaseViewModel而不是PersonalViewModel。模型聯編程序是創建模型的模塊,並且由於您的操作模型爲BaseViewModel,它會創建一個BaseViewModel對象。

我會建議您爲每個步驟創建單獨的操作。每個行動都應該有相應的模式。在這種情況下,我也認爲你應該更喜歡構圖而不是繼承。

public class FullModel 
{ 
    public FirstStepModel FirstStep {get;set;} 
    public SecondStepModel SecondStep {get;set;} 
} 

然後,一旦你開始你的流量(在例如第一步),您可以創建一個FullModel對象,並存儲在某個地方(會議/餅乾/序列化爲文字,發送給客戶端 - 這是真正達到您)。

然後在控制器,你將有

[HttpGet] 
public ActionResult ProcessFirst() 
{  
    HttpContext.Session["FullModel"] = new FullModel(); //at the beginning store full model in session 
    var firstStepModel = new FirstsStepModel(); 
    return View(firstStepModel) //return a view for first step 
} 


[HttpPost] 
public ActionResult ProcessFirst(FirstStepModel model) 
{ 
    if(this.ModelState.IsValid) 
    { 
     var fullModel = HttpContext.Session["FullModel"] as FullModel; //assuming that you stored it in session variable with name "FullModel" 
     if(fullModel == null) 
     { 
      //something went wrong and your full model is not in session.. 
      //return some error page 
     } 
     fullModel.FirstStep = model; 
     HttpContext.Session["FullModel"] = fullModel; // update your session with latest model 
     var secondStepModel = new SecondStepModel(); 
     return View("SecondStepView", secondStepModel) //return a view for second step 
    } 

    // model is invalid ... 
    return View("FirstStepView", model);  
} 

[HttpPost] 
public ActionResult ProcessSecond(SecondStepModel model) 
{ 
    var fullModel = HttpContext.Session["FullModel"] as FullModel; //assuming that you stored it in session variable with name "FullModel" 
    if(fullModel == null) 
    { 
     //something went wrong and your full model is not in session.. 
     //return some error page 
    } 
    fullModel.SecondStep = model; 
    HttpContext.Session["FullModel"] = fullModel; // update your session with latest model 
    var thirdStepModel = new ThirdStepModel(); 
    return View("ThirdStepModel", thirdStepModel); //return a view for a third step 
} 

當然,你應該提取所有的共享代碼可重用的一些方法。 而這完全取決於你使用何種持久性技術來傳遞FullModel之間的請求。

如果您仍然傾向於使用一個Action解決方案,則需要創建一個定製模型聯編程序,該聯編程序將根據從客戶端傳遞的一些數據創建派生實例。看看這thread

+0

解決此問題的方法是什麼?任何想法?擴展模型BInder將工作? – user2066540

0

我想出了一個通用的方式來處理這種情況使用模型綁定。這裏是.. 您可能需要從DefaultBinder獲得一個擴展模型綁定器來實現返回您的模型類型。

public class WizardModelBinder : DefaultModelBinder 
{ 
    protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType) 
    { 
     var viewIdContext = bindingContext.ValueProvider.GetValue("ViewId"); 
     int StepId = 0; 

     if (!int.TryParse(viewIdContext, out StepId)) 
      throw new InvalidOperationException("Incorrect view identity"); 
     //This is my factory who gave me child view based on the next view id you can play around with this logic to identify which view should be rendered next 
     var model = WizardFactory.GetViewModel(StepId); 

     bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, model.GetType()); 
     bindingContext.ModelMetadata.Model = model; 
     return model; 
    } 
} 

你會從你的gloab ASX註冊該粘結劑像

ModelBinders.Binders.Add(typeof(BaseViewModel), new WizardModelBinder()); 

感謝所有誰responsed到我的查詢.. !!讓我知道你們是否有任何問題。

快樂編碼..!