ASP.NET MVC将BaseViewModel转换为DeriveViewModel

ASP.NET MVC将BaseViewModel转换为DeriveViewModel,asp.net,asp.net-mvc,casting,viewmodel,Asp.net,Asp.net Mvc,Casting,Viewmodel,我正在开发一个注册流程,用户来这里填写5页来完成一个流程。我决定一步一步地使用多个视图、一个控制器和一个ProcessNext操作方法。每次调用进程Next时,它都会得到原始视图和Next视图。因为每个视图都有自己的视图模型,所以我创建了一个基本视图模型,所有视图特定的视图模型都是从该模型派生的。现在的问题是,casting正在抛出一个异常。。下面是示例代码 基本视图模型 public class BaseViewModel { public string viewName; } 个

我正在开发一个注册流程,用户来这里填写5页来完成一个流程。我决定一步一步地使用多个视图、一个控制器和一个ProcessNext操作方法。每次调用进程Next时,它都会得到原始视图和Next视图。因为每个视图都有自己的视图模型,所以我创建了一个基本视图模型,所有视图特定的视图模型都是从该模型派生的。现在的问题是,casting正在抛出一个异常。。下面是示例代码

基本视图模型

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" />
这会失败并引发类型case异常,为什么


我的想法是只使用一个动作方法来转换所有这些派生的视图模型,并发送到一个公共类进行验证和处理。请帮我解决这个问题。。谢谢

出现此异常的原因是您的模型类型是
BaseViewModel
,而不是
PersonalViewModel
。模型绑定器是创建模型的绑定器,因为动作的模型是
BaseViewModel
,所以它创建一个
BaseViewModel
对象

我建议您为每个步骤创建单独的操作。每个动作都应该有相应的模型。我还认为,在这种情况下,您应该更喜欢组合而不是继承

public class FullModel
{
    public FirstStepModel FirstStep {get;set;}
    public SecondStepModel SecondStep {get;set;}
}
然后,一旦启动流(例如第一步),您就可以创建一个
FullModel
对象并将其存储在某个位置(会话/cookie/序列化为文本并发送到客户端-这完全取决于您)

然后在控制器中,您将拥有

[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
完全取决于您使用什么持久性技术


如果您仍然喜欢使用一个操作解决方案,则需要创建一个自定义模型绑定器,该绑定器将基于从客户端传递的一些数据创建派生实例。看看这个

我找到了一种使用模型绑定器处理这种情况的通用方法。给你。。 您可能需要使用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());
感谢所有回答我问题的人。。!!如果你们有任何问题,请告诉我


快乐的编码

因为
viewModelData
不是
PersonalViewModel
,所以不能将基类型强制转换为派生类型。在任何情况下,这都不可能起作用,因为您回发了
BaseViewModel
,因此与
PersonalViewModel
相关的所有内容都将丢失。。我很擅长将基类类型划分为派生类。。正确的?。。那么,我们可以做些什么来让它工作呢?任何猜测?在第一步中,您发回
public ActionResult步骤1(PersonalViewModel)
,该步骤保存数据,然后重定向到一个GET方法,该方法呈现您的
Step2ViewModel
视图,该视图发回
public ActionResult步骤2(Step2ViewModel模型)
等等。
BaseViewModel
除了可能包含一个所有步骤模型都通用的
ID
属性和“我很乐意将基类类型强制转换为派生的..对吧?”之外没有任何意义。不,您不能这样做。但是你可以用另一种方式来做。有什么办法可以让这一切发生呢?有什么想法吗?扩展模型绑定器会起作用吗?
 ModelBinders.Binders.Add(typeof(BaseViewModel), new WizardModelBinder());