ASP.NET MVC CRUD Validation
- by Ricardo Peres
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:
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;
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;
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!