Sunday, November 5, 2017

Validating MVC model extracted from session

Leave a Comment

I’m making an MVC online web shopping app, so after the shopping cart page I’ve got ProcessStepOne action in which the user should fill his data.

[Authentication]  public ActionResult ProcessStepOne() {      ProcessOrderViewModel model = GetOrderData();                 return View("ProcessOrderStepOne", model);  }   private ProcessOrderViewModel GetOrderData() {     ProcessOrderViewModel model = (ProcessOrderViewModel)Session["Process"];     if(model==null)     {         model = new ProcessOrderViewModel();     }     return model; } 

My ProcessOrderViewModel model is:

public class ProcessOrderViewModel  {     public ProcessOrderViewModel()     {         this.PrivateIndividualData = new PrivateIndividualModel();         this.OrderDiscoutPrice = new OrderDiscountPriceModel();     }     public PrivateIndividualModel PrivateIndividualData { get; set; }     public OrderDiscountPriceModel OrderDiscoutPrice { get; set; } } 

And my View ProcessOrderStepOne is:

@model  ProcessOrderViewModel  <form id="formOrderData" method="post" action="@Url.Action("ProcessStepTwo")">                <div class="row">         <div class="col-xs-12 col-sm-6">             <div class="form-group">                 <label> First Name </label>                 @Html.TextBoxFor(x => x.PrivateIndividualData.FirstName, new { @class = "form-control" })                 @Html.ValidationMessageFor(x => x.PrivateIndividualData.FirstName)             </div>         </div>          <div class="col-xs-12 col-sm-6">             <div class="form-group">                 <label> Last Name </label>                 @Html.TextBoxFor(x => x.PrivateIndividualData.Family, new { @class = "form-control" })                 @Html.ValidationMessageFor(x => x.PrivateIndividualData.Family)             </div>         </div>          <div class="col-xs-12 col-sm-6">             <div class="form-group">                 <label>Email</label>                 @Html.TextBoxFor(x => x.PrivateIndividualData.Email, new { @class = "form-control" })                 @Html.ValidationMessageFor(x => x.PrivateIndividualData.Email)             </div>         </div>          <div class="col-xs-12 col-sm-6">             <div class="form-group">                 <label for="tel">@StringResources.GetResourceString("UserManagement", "Register_PhoneLabel")</label>                 @Html.TextBoxFor(x => x.PrivateIndividualData.Telephone, new { @class = "form-control" })                 @Html.ValidationMessageFor(x => x.PrivateIndividualData.Telephone)             </div>         </div>     </div> </form> 

So, my second step is just checking the values the user has entered and then show him for verification. If everything is OK I save the data in the session so the user can return to the previous ProcessStepOne action or proceed to making order with the MakeOrder action.

public ActionResult ProcessStepTwo(ProcessOrderViewModel model) {     if (ModelState.IsValid)     {         Session["Process"] = model;         return View("ProcessOrderStepTwo", model);     }     return View("ProcessOrderStepOne", model);  } 

And the view is:

@model ProcessOrderViewModel  <section class="form-section">                         <p>         <a href='@Url.Action("ProcessStepOne")'>CHANGE</a>         <span class="text-semibold">Name:</span> @Model.PrivateIndividualData.FirstName <br>         <span class="text-semibold">Last Name:</span> @Model.PrivateIndividualData.Family <br>         <span class="text-semibold">E-mail:</span>  @Model.PrivateIndividualData.Email<br>         <span class="text-semibold">Телефон:</span>@Model.PrivateIndividualData.Telephone <br>                                </p> </section> <a href='@Url.Action("MakeOrder")'>PROCEED TO MAKE ORDER</a> 

And, here is my last action which just gets the data from the session:

public ActionResult MakeOrder() {     var data = (ProcessOrderViewModel)System.Web.HttpContext.Current.Session["Process"];        // make order with this data     return View("Thank You"); } 

So my questions are: in the MakeOrder action I just take the model from the session without any verification. How can I validate it again and also is it right storing the data in session so I can return to make modifications or proceed to make an order. Is this the right thing to do because I can't think of another way.

1 Answers

Answers 1

In the MakeOrder action I just take the model from the session without any verification. How can I validate it again?

You can use TryValidateModel in your controller to re-validate your model after retrieving it from Session. However, from my testing it appears that this method only validates one level deep in the model. With this in mind, you code would be something like the following:

public ActionResult MakeOrder() {     var data = (ProcessOrderViewModel)System.Web.HttpContext.Current.Session["Process"];       bool individualDataValid = TryValidateModel(data.PrivateIndividualData);     bool discountDataValid = TryValidateModel(data.OrderDiscoutPrice);      if (individualDataValid && discountDataValid)     {         // make order with this data         return View("Thank You");     }      //Error condition     return View("Error"); } 

Is it right storing the data in session so I can return to make modifications or proceed to make an order. Is this the right thing to do because I can't think of another way.

Personally, I avoid using Session if I can. However, I think it is perfectly justifiable for a "Shopping Basket" requirement such as yours. What I would say is that from a maintenance and testing perspective, it may be better if you create a wrapper object for Session access. See Session variables in ASP.NET MVC.

This has the following benefits:

  • All your Session access is in one place. Not scattered liberally across controllers.
  • No "Magic Strings" used across your solution for session access.
  • As an added bonus, because you have abstracted session access out into an object, your controllers can be more "testable" (provided it is not a static wrapper).
If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment