我正在开发一个注册流程,其中用户来到并填写5页以完成一个过程。我决定一步一步地拥有多个视图和一个控制器以及一个ProcessNext操作方法。每次调用Process Next时,它都会获得原始视图和下一个视图。由于每个视图与自己的视图模型相关联,因此我创建了一个基本视图模型,所有视图模型都是从中派生出来的。现在的问题是,正在抛出异常..这里是示例代码
基本视图模型
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 :(得分:0)
您看到此例外的原因是您的模型类型为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
的持久性技术。
如果您仍然希望使用一个Action解决方案,则需要创建一个自定义模型绑定器,该绑定器将根据从客户端传递的某些数据创建派生实例。看一下这个thread
答案 1 :(得分: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());
感谢所有回复我的查询的人.. !!如果你们有任何问题,请告诉我。
快乐编码.. !!