As B2K Answer pointed out, using a ViewModel has advantages. I am not a fan of consistently mapping fields back and forth over and over, so I like to use MetaData and Validation classes to encapsulate that concept.
public TheMainClass
{
public string Prop1 { get; set; }
public string Prop2 { get; set; }
public string Prop3 { get; set; }
public string Prop4 { get; set; }
}
If I only display and validate each prop for each view, then I would create 4 models designed specifically for validation:
[Metadata(typeof(Main1Model.IView1Validation))]
public Main1Model : TheMainClass
{
internal interface IView1Validation
{
[Required]
string Prop1 { get; set; }
[ScaffoldColumn(false)]
string Prop2 { get; set; }
//etc
}
}
ViewModel2:
[Metadata(typeof(IView2Validation))]
public Main2Model : TheMainClass
{
internal interface IView1Validation
{
[HiddenInput(DisplayValue = false)]
[Required]
string Prop1 { get; set; }
[Required]
string Prop2 { get; set; }
//etc
}
}
And so forth. As the views progress if someone decides, using a browser tool, to fudge a hidden field, you still have the validation.
One ViewModel will encapsulate all views models: (I always do this as B2K recommends as well)
public MainViewModel
{
public MainModel { get; set; }
}
etc..
Then Actions would look something like:
[HttpPost]
public ActionResult View1(MainViewModelmodel)
{
if (ModelState.IsValid)
{
TempData["View1"] = model;
return this.RedirectToAction("View2");
}
return this.View(model);
}
public ActionResult View2()
{
model = TempData["View"] as Main1ViewModel;
if (model == null)
{
return this.RedirectToAction("View1");
}
return this.View(model)
}
[HttpPost]
public ActionResult View2(MainViewModel model)
{
// and so on (like HttpPost View1
}
Then you might be asking.. but wait how does this work? The ViewModel is using the base type, and that is the magic of MVC. You'll notice that View2.cshtml
is strongly-typed to MainViewModel
but Views use the Concrete Type passed in, not the defined typed passed in.
All views would look something like (might even be able to be the same view):
@model MainViewModel
@EditFor(m => m.MainModel.Prop1)
@EditFor(m => m.MainModel.Prop2)
@EditFor(m => m.MainModel.Prop3)
@EditFor(m => m.MainModel.Prop4)
If Model1View is passed in with scaffold fals
e, the editfor()s won't create any html elements.
As the user progresses and you've specified [HiddenInput]
the editfor()s create a hidden field.
The last bit of awesome-sauce is two-fold; first you don't have to persist the model in memory (because each model is fully-passed in to the view), and secondly the back button works because the model is stored in the view inputs (including hidden fields)