On POST , if validation failed and before sending back the ViewModel to the same View with Model State errors, do you rebuild ViewModel for all SelectLists, ReadOnly fields etc? right now I have separate methods for Fill First Time(for GET Edit-Method) / Rebuild ViewModels from domain objects, what is the best practice so I can be DRY and also not have to change two methods any time I add a new readonly property to ViewModel?
My Solution: Followed this Pattern
Followed pattern suggested here: https://stackoverflow.com/a/2775656/57132 In IModelBuilder Implementation
Build(..)
{
var viewModel = new ViewModel();
// and Fill all Non-ReadOnly fields
...
...
call CompleteViewModel(viewModel)
}
CompleteViewModel(ViewModel viewModel)
{
//Fill all ReadOnly & SelectLists
...
}
The reason I went with this solution is because I don't want to store stuff on server to retrieve across the HTTP Requests
What ViewModel is. In ASP.NET MVC, ViewModels are used to shape multiple entities from one or more models into a single object. This conversion into single object provides us better optimization. You can see the concept of ViewModel in the image below.
While the ViewModel is an optional pattern the Controller is a must, if you are going the MVC way. The ViewModel encapsulates presentation logic and state, The Controller orchestrates all the Application Flow.
A model is usually more closely related to how your data is stored (database, services, etc.) and the model will closely resemble those. The ViewModel on the other hand is closely related to how your data is presented to the user. It is usually a flatten version of your model, denormalized, etc.
In ASP.NET MVC, ViewModel is a class that contains the fields which are represented in the strongly-typed view. It is used to pass data from controller to strongly-typed view.
I don't rebuild it, because I don't stay at POST. I follow POST-REDIRECT-GET pattern, so if I post to /User/Edit/1 using POST HTTP method, I get redirected to /User/Edit/1 uasing GET.
ModelState
is transferred to TempData
to follow Post-Redirect-Get and be availabe at GET call. View model is built in one place, at GET call. Example:
[HttpPost]
[ExportModelStateToTempData]
public ActionResult Edit(int id, SomeVM postedModel)
{
if (ModelState.IsValid) {
//do something with postedModel and then go back to list
return RedirectToAction(ControllerActions.List);
}
//return back to edit, because there was an error
return RedirectToAction(ControllerActions.Edit, new { id });
}
[ImportModelStateFromTempData]
public ActionResult Edit(int id)
{
var model = //create model here
return View(ControllerActions.Edit, model);
}
This is code for attributes importing/exporting ModelState
:
public abstract class ModelStateTempDataTransferAttribute : ActionFilterAttribute
{
protected static readonly string Key = typeof(ModelStateTempDataTransferAttribute).FullName;
}
public class ExportModelStateToTempDataAttribute : ModelStateTempDataTransferAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
//Only export when ModelState is not valid
if (!filterContext.Controller.ViewData.ModelState.IsValid)
{
//Export if we are redirecting
if ((filterContext.Result is RedirectResult) || (filterContext.Result is RedirectToRouteResult))
{
filterContext.Controller.TempData[Key] = filterContext.Controller.ViewData.ModelState;
}
}
base.OnActionExecuted(filterContext);
}
}
public class ImportModelStateFromTempDataAttribute : ModelStateTempDataTransferAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
ModelStateDictionary modelState = filterContext.Controller.TempData[Key] as ModelStateDictionary;
if (modelState != null)
{
//Only Import if we are viewing
if (filterContext.Result is ViewResult)
{
filterContext.Controller.ViewData.ModelState.Merge(modelState);
}
else
{
//Otherwise remove it.
filterContext.Controller.TempData.Remove(Key);
}
}
base.OnActionExecuted(filterContext);
}
}
The simplest solution would be to pass in you viewModel to the method and account for null
private MyViewModel BuildViewModel(MyViewModel model = null)
{
model = model ?? new MyViewModel();
model.ReadOnlyList = new .....
.
.
return model;
}
for Create:
var model = BuildViewModel();
for rebuild:
model = buildViewModel(model);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With