0

I have an MVC4 registration form that employs two custom remote validators. The first validator checks for email uniqueness, and works properly. The second checks number of uses for a voucher code. It correctly displays a message after entering a voucher code, but it fails to honor the custom remote validation at the point of submission.

In other words, you can enter a voucher code and see the "Cannot use voucher..." message from the remote validator. But you can still submit the form.

This is the abbreviated markup for the form, with just the relevant fields and the submit button. The full form is much larger. The email fields, which use custom validation successfully, are retained in this example for comparison. You can see the RegistrationVoucherCode field and validator near the end of the form.

@using (Html.BeginForm("Index", "Registration", FormMethod.Post))
  {
     <div class="row">
        <div class="col-lg-6 col-md-6 col-xs-6 field_wrapper">
           <div class="form_label">@Html.LabelFor(m => m.EmailAddress)</div>
           <div class="form_field">@Html.TextBoxFor(m => m.EmailAddress)</div>
           <div class="form_validator">@Html.ValidationMessageFor(m => m.EmailAddress)</div>
        </div>
        <div class="col-lg-6 col-md-6 col-xs-6 field_wrapper">
           <div class="form_label">Confirm Email</div>
           <div class="form_field">@Html.TextBoxFor(m => m.ConfirmEmail)</div>
           <div class="form_validator">@Html.ValidationMessageFor(m => m.ConfirmEmail)</div>
        </div>
     </div>
     <div class="row">
        <div class="col-lg-6 col-md-6 col-xs-6 field_wrapper">
           <div class="form_label">@Html.LabelFor(m => m.RegistrationVoucherCode)</div>
           @{ 
              string displayVoucherCode = Model.RegistrationVoucherCode.ToString();
              if (Model.RegistrationVoucherCode == 0)
              {
                 displayVoucherCode = string.Empty;
              }
           }
           <div class="form_field">@Html.TextBoxFor(m => m.RegistrationVoucherCode, new { Value = displayVoucherCode, maxlength = 7 })</div>
           <div class="form_validator">@Html.ValidationMessageFor(m => m.RegistrationVoucherCode)</div>
        </div>
        <div class="col-lg-6 col-md-6 col-xs-6 field_wrapper">
        </div>
     </div>
     <div class="row">
        <div class="col-xs-12">
           <input type="submit" id="submitForm" value="Next" class="standard_button right_button" />
        </div>
     </div>
  }

This is related code from my ProfileModel. The full model is much larger, so only relevant code is presented here. At the end of this you can see RegistrationVoucherCode.

using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;

namespace SW.CEA.WebSite.Models.Registration
{
public class ProfileModel
{
  public ProfileModel()
  {
  }

  public Profile Profile { get; set; }


  [Required(ErrorMessage = "Confirm Email is required.")]
  [Display(Name = "Confirm Email")]
  [StringLength(128)]
  [RegularExpression(@"\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*", ErrorMessage = "Confirm Email Address is Not Valid")]
  [System.Web.Mvc.Compare("EmailAddress", ErrorMessage = "Email addresses do not match..")]
  public string ConfirmEmail
  {
     get
     {
        return Profile.ConfirmEmail;
     }
     set
     {
        Profile.ConfirmEmail = value;
     }
  }

  [Required(ErrorMessage = "Email Address is required.")]
  [Display(Name = "Email")]
  [StringLength(128)]
  [Remote("ValidateEmailUniqueness", "Registration")]
  [RegularExpression(@"\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*", ErrorMessage = "Email Address is Not Valid")]
  public string EmailAddress
  {
     get
     {
        return Profile.EmailAddress;
     }
     set
     {
        Profile.EmailAddress = value;
     }
  }

  [Required(ErrorMessage = "Order Code is required.")]
  [Display(Name = "Order Code")]
  [Remote("ValidateVoucherCode", "Registration")]
  public int RegistrationVoucherCode
  {
     get
     {
        return Profile.RegistrationVoucherCode;
     }
     set
     {
        Profile.RegistrationVoucherCode = value;
     }
  }

}
}

And these are custom validators from my RegistrationController. Again, email address validators appear here for comparison. My problem is with enforcing the ValidateVoucherCode custom validator at the point of form submission.

  private bool IsEmailUnique(string EmailAddress)
  {
     var profile = ProfileRepository.GetProfile(EmailAddress);
     return (profile == null);
  }

  [HttpGet]
  public JsonResult ValidateEmailUniqueness(string EmailAddress)
  {
     if (!IsEmailUnique(EmailAddress))
     {
        return Json("Error, email address is already registered, please sign in.", JsonRequestBehavior.AllowGet);
     }
     return Json(true, JsonRequestBehavior.AllowGet);
  }

  [HttpGet]
  public JsonResult ValidateVoucherCode(int RegistrationVoucherCode)
  {
     var voucher = VoucherRepository.GetVoucherWithProfiles(RegistrationVoucherCode);
     if (voucher == null)
     {
        return Json("Invalid Order Code", JsonRequestBehavior.AllowGet);
     }
     if (voucher.Profiles.Count >= Settings.Default.MaxVoucherUses)
     {
        return Json("Cannot user voucher, will exceed maximum number of voucher uses.", JsonRequestBehavior.AllowGet);
     }
     return Json(true, JsonRequestBehavior.AllowGet);
  }

The message, "Cannot user voucher, will exceed maximum number of voucher uses," will successfully appear on the client in this ValidationMessageFor when an overused validation code is entered. This again is from the form.

@Html.TextBoxFor(m => m.RegistrationVoucherCode, new { Value = displayVoucherCode, maxlength = 7 })
@Html.ValidationMessageFor(m => m.RegistrationVoucherCode)

Upon tabbing off the form field, debugger shows this remote validator being hit.

[HttpGet]
public JsonResult ValidateVoucherCode(int RegistrationVoucherCode)

So the ValidateVoucherCode custom validator is doing part of it's job. It's showing the "Cannot use voucher..." message when I tab off the field. But it doesn't prevent the form from being submitted. By contrast, the unique email address validator on the same form will prevent form submission. I need the RegistrationVoucherCode validator to operate in the same manner. Thanks for your help.

Ken Palmer
  • 2,355
  • 5
  • 37
  • 57
  • jquery.unobtrusive-ajax.min.js, jquery.validate.min.js, jquery.validate.unobtrusive.min.js are you using all of these above jqueries in your cshtml form? – Krunal Patil May 03 '14 at 05:14
  • Thanks for responding @KrunalPatil. Scripts I originally used were: jquery-2.1.0.min.js, jquery.validate.min.js, jquery.validate.unobtrusive.min.js, bootstrap.min.js. – Ken Palmer May 06 '14 at 12:31
  • jquery.validate.unobtrusive.min.js is the culprit. But is your issue solved ? – Krunal Patil May 06 '14 at 12:33
  • That's interesting. My issue is solved, but apparently for a different reason. If I replace jquery-2.1.0.min.js with https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.js, the validation works. – Ken Palmer May 06 '14 at 12:35
  • and mine got solved by removing the jquery.validate.unobtrusive.min.js from my cshtml page. but good to know your isse was resolved. Happy Coding.!! – Krunal Patil May 06 '14 at 12:37
  • After removing the unobtrusive script, now the form doesn't dynamically attempt to validate. Here is the combination of scripts that works. https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.js, jquery.validate.min.js, jquery.validate.unobtrusive.min.js. Makes me wonder why the jquery 2.1.0 fails. At least this is working now. Thanks for your help. – Ken Palmer May 06 '14 at 12:38
  • I didn't do anything buddy, it was you who did it. But thanks next time I'll try your method and see if it resolved my issue. – Krunal Patil May 06 '14 at 12:40

1 Answers1

0

The solution was to replace jquery-2.1.0.min.js with https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.js.

The scripts that my form presently uses are:

https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.js
jquery.validate.min.js
jquery.validate.unobtrusive.min.js
Ken Palmer
  • 2,355
  • 5
  • 37
  • 57
  • Additionally, if I apply the latest jQuery library from Google, instead of the 1.7.1 version, it begins failing. https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.js – Ken Palmer May 06 '14 at 13:01
  • I'll bet that is related to a disconnect between my local instances of the jquery.validate libraries on my PC. Probably I'll need to target the Microsoft hosted instances, and correlate them with whatever version of jQuery that we're using. Those libraries are here. http://www.asp.net/ajaxlibrary/cdn.ashx – Ken Palmer May 06 '14 at 13:04
  • That's it. The versions all need to correspond. This all works together. – Ken Palmer May 06 '14 at 13:13