ASP.NET MVC CRUD Validation

One thing I didn’t refer on my previous post on ASP.NET MVC CRUD with AJAX was how to retrieve model validation information into the client.

We want to send any model validation errors to the client in the JSON object that contains the ProductId, RowVersion and Success properties, specifically, if there are any errors, we will add an extra Errors collection property. Here’s how:

   1: [HttpPost]
   2: [AjaxOnly]
   3: [Authorize]
   4: public JsonResult Edit(Product product)
   5: {
   6:     if (this.ModelState.IsValid == true)
   7:     {
   8:         using (ProductContext ctx = new ProductContext())
   9:         {
  10:             Boolean success = false;
  11:  
  12:             ctx.Entry(product).State = (product.ProductId == 0) ? EntityState.Added : EntityState.Modified;
  13:  
  14:             try
  15:             {
  16:                 success = (ctx.SaveChanges() == 1);
  17:             }
  18:             catch (DbUpdateConcurrencyException)
  19:             {
  20:                 ctx.Entry(product).Reload();
  21:             }
  22:  
  23:             return (this.Json(new { Success = success, ProductId = product.ProductId, RowVersion = Convert.ToBase64String(product.RowVersion) }));
  24:         }
  25:     }
  26:     else
  27:     {
  28:         Dictionary<String, String> errors = new Dictionary<String, String>();
  29:  
  30:         foreach (KeyValuePair<String, ModelState> keyValue in this.ModelState)
  31:         {
  32:             String key = keyValue.Key;
  33:             ModelState modelState = keyValue.Value;
  34:  
  35:             foreach (ModelError error in modelState.Errors)
  36:             {
  37:                 errors[key] = error.ErrorMessage;
  38:             }
  39:         }
  40:  
  41:         return (this.Json(new { Success = false, ProductId = 0, RowVersion = String.Empty, Errors = errors }));
  42:     }
  43: }

As for the view, we need to change slightly the onSuccess JavaScript handler on the Single view:

   1: function onSuccess(ctx)
   2: {
   3:     if (typeof (ctx.Success) != 'undefined')
   4:     {
   5:         $('input#ProductId').val(ctx.ProductId);
   6:         $('input#RowVersion').val(ctx.RowVersion);
   7:  
   8:         if (ctx.Success == false)
   9:         {
  10:             var errors = '';
  11:  
  12:             if (typeof (ctx.Errors) != 'undefined')
  13:             {
  14:                 for (var key in ctx.Errors)
  15:                 {
  16:                     errors += key + ': ' + ctx.Errors[key] + '\n';
  17:                 }
  18:  
  19:                 window.alert('An error occurred while updating the entity: the model contained the following errors.\n\n' + errors);
  20:             }
  21:             else
  22:             {
  23:                 window.alert('An error occurred while updating the entity: it may have been modified by third parties. Please try again.');
  24:             }
  25:         }
  26:         else
  27:         {
  28:             window.alert('Saved successfully');
  29:         }
  30:     }
  31:     else
  32:     {
  33:         if (window.confirm('Not logged in. Login now?') == true)
  34:         {
  35:             document.location.href = '<%
   1: : FormsAuthentication.LoginUrl 
%>?ReturnURL=' + document.location.pathname;
  36:         }
  37:     }
  38: }

The logic is as this:

  1. If the Edit action method is called for a new entity (the ProductId is 0) and it is valid, the entity is saved, and the JSON results contains a Success flag set to true, a ProductId property with the database-generated primary key and a RowVersion with the server-generated ROWVERSION;
  2. If the model is not valid, the JSON result will contain the Success flag set to false and the Errors collection populated with all the model validation errors;
  3. If the entity already exists in the database (ProductId not 0) and the model is valid, but the stored ROWVERSION is different that the one on the view, the result will set the Success property to false and will return the current (as loaded from the database) value of the ROWVERSION on the RowVersion property.

On a future post I will talk about the possibilities that exist for performing model validation, stay tuned!

                             

4 Comments

  • One question? It's better to use the MVC Controller to make the JSON response insted of creating a WCF Service to do that!?!?


    regards
    Paulo Aboim Pinto

  • @Paulo:
    I'd say it depends; using a controller, you minimize the dependencies. Same problem as deciding whether to use a control that implements ICallbackEventHandler versus calling an external web service/handler in web forms.
    No absolute solution here, your opinion is as good as mine! ;-)

  • I think that using the MVC Controller looks better ... and yes ... it will make the dependency problem go away in out target application.

    I'm just giving small steps in this area right now ... just making questions.


    Regards
    Paulo Aboim Pinto

  • @Paulo:
    Feel free to drop by and share your questions/thoughts! ;-)
    I will have another post on MVC validation by tomorrow (I hope...)

Comments have been disabled for this content.