title: ASP.NET MVC3: ValidationType ModelClientValidationRule
body: <p>I just created a sample MVC3 application to learn validation. It is using DataAnnotations. I have created a <strong>custom ValidationAttribute</strong> named  CustomStartLetterMatch. It is implementing “System.Web.Mvc.IClientValidatable”. I have corresponding client-side code written with unobtrusive jQuery. This is working as expected.</p>
  
  <p>About the custom validator: It compares the first name input and last name input. It throws error if first character of both of them are not same. </p>
  
  <p>As I said, the application is working fine. But when I looked at the <code>rule.ValidationType = "greaterdate";</code> I got confused. I wanted to change it to something else like “anotherDefaultType”. When I am changing it, it fails with jQuery error. </p>
  
  <ol>
  <li>What is the reason for this? </li>
  <li>What are the available ValidationTypes?</li>
  <li>What is the suggested approach to change the ValidationType in this scenari</li>
  </ol>
  
  <p>CODE:</p>
  
  <pre><code>using System;
  using System.ComponentModel.DataAnnotations;
  using System.Collections.Generic;
  namespace MyValidationTEST
  {
      public class Person
      {
      [Required(ErrorMessage = "First name required")]
      public string FirstName { get; set; }
  
      [CustomStartLetterMatch("FirstName")]
      [StringLength(5,ErrorMessage = "Must be under 5 characters")]
      public string LastName { get; set; }
  
      [Range(18,50,ErrorMessage="Must be between 18 and 50")]
      public int Age { get; set; }
  
  }
  
  
  
  public sealed class CustomStartLetterMatch : ValidationAttribute, System.Web.Mvc.IClientValidatable 
  {
  
      private const string _defaultErrorMessage = " First letter of '{0}' must be same as first letetr of '{1}'";
      private string _basePropertyName;
  
      public CustomStartLetterMatch(string basePropertyName)
          : base(_defaultErrorMessage)
      {
          _basePropertyName = basePropertyName;
      }
  
  
      //Override FormatErrorMessage Method
      public override string FormatErrorMessage(string name)
      {
          return string.Format(_defaultErrorMessage, name, _basePropertyName);
      }
  
  
      //Override IsValid
      protected override ValidationResult IsValid(object value, System.ComponentModel.DataAnnotations.ValidationContext validationContext)
      {
          //Get PropertyInfo Object
          var basePropertyInfo = validationContext.ObjectType.GetProperty(_basePropertyName);
          var baseValue = (string)basePropertyInfo.GetValue(validationContext.ObjectInstance, null);
          var currentValue = (string)value;
  
  
          string firstLetterBaseValue = baseValue.Substring(0, 1);
          string firstLetterCurrentValue = currentValue.Substring(0, 1);
  
          //Comparision
          if (!string.Equals(firstLetterBaseValue, firstLetterCurrentValue))
          {
              var message = FormatErrorMessage(validationContext.DisplayName);
              return new ValidationResult(message);
          }
  
          //Default return - This means there were no validation error
          return null;
      }
  
  
      public IEnumerable&lt;System.Web.Mvc.ModelClientValidationRule&gt; GetClientValidationRules(System.Web.Mvc.ModelMetadata metadata, System.Web.Mvc.ControllerContext context)
      {
          var rule = new System.Web.Mvc.ModelClientValidationRule();
          rule.ErrorMessage = FormatErrorMessage(metadata.GetDisplayName());
          rule.ValidationParameters.Add("other", _basePropertyName);
          rule.ValidationType = "greaterdate";
          yield return rule;
      }
  
  
  
  }
  </code></pre>
  
  <p>}</p>
  
  <p>VIEW</p>
  
  <pre><code>@model MyValidationTEST.Person
  
  @{
  ViewBag.Title = "Create";
  }
  
  &lt;h2&gt;Create&lt;/h2&gt;
  
  &lt;script src="@Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"&gt;  &lt;/script&gt;
  
  @*UnObtrusive*@
  &lt;script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"&gt;&lt;/script&gt;
  &lt;script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"&gt;&lt;/script&gt;
  
  
  
  &lt;script type="text/javascript"&gt;
  
  /*Register adapter - addSingleVal*/
  jQuery.validator.unobtrusive.adapters.addSingleVal("greaterdate", "other");
  
  
  /*Validation type names in unobtrusive client validation rules must consist of only lowercase letters*/
  
  /*Add Method*/
  jQuery.validator.addMethod("greaterdate",
                                      function (val, element, other) 
                                      {
  
                                          var modelPrefix = element.name.substr(0, element.name.lastIndexOf(".") + 1)
                                          var otherVal = $("[name=" + modelPrefix + other + "]").val();
  
                                          if (val &amp;&amp; otherVal) 
                                          {
                                              var lastNameFirstLetter = val.substr(0, 1);
                                              var firstNameFirstLetter = otherVal.substr(0, 1);
  
                                              if (lastNameFirstLetter != firstNameFirstLetter) 
                                              {
                                                  return false;
                                              }
                                          }
                                          return true;
                                      });
  
  
  &lt;/script&gt;
  
  
  @using (Html.BeginForm()) {
  @Html.ValidationSummary(true)
  &lt;fieldset&gt;
      &lt;legend&gt;Person&lt;/legend&gt;
  
      &lt;div class="editor-label"&gt;
          @Html.LabelFor(model =&gt; model.FirstName)
      &lt;/div&gt;
      &lt;div class="editor-field"&gt;
          @Html.EditorFor(model =&gt; model.FirstName)
          @Html.ValidationMessageFor(model =&gt; model.FirstName)
      &lt;/div&gt;
  
      &lt;div class="editor-label"&gt;
          @Html.LabelFor(model =&gt; model.LastName)
      &lt;/div&gt;
      &lt;div class="editor-field"&gt;
          @Html.EditorFor(model =&gt; model.LastName)
          @Html.ValidationMessageFor(model =&gt; model.LastName)
      &lt;/div&gt;
  
      &lt;div class="editor-label"&gt;
          @Html.LabelFor(model =&gt; model.Age)
      &lt;/div&gt;
      &lt;div class="editor-field"&gt;
          @Html.EditorFor(model =&gt; model.Age)
          @Html.ValidationMessageFor(model =&gt; model.Age)
      &lt;/div&gt;
  
      &lt;p&gt;
          &lt;input type="submit" value="Create" /&gt;
      &lt;/p&gt;
  &lt;/fieldset&gt;
  }
  
  &lt;div&gt;
  @Html.ActionLink("Back to List", "Index")
  &lt;/div&gt;
  </code></pre>
  
  <p>CONTROLLER:</p>
  
  <pre><code>using System.Web.Mvc;
  namespace MyValidationTEST.Controllers
  {
  public class RelativesController : Controller
  {
  
      // GET: /Relatives/
      public ActionResult Index()
      {
          return View();
      }
  
  
  
      // GET: /Relatives/Create
      public ActionResult Create()
      {
          Person person = new Person();
          return View(person);
      }
  
  
      // POST: /Relatives/Create
      [HttpPost]
      public ActionResult Create(Person relativeToAdd)
      {
          if (ModelState.IsValid)
          {
              return RedirectToAction("Index");
          }
          return View(relativeToAdd);
      }
  
      }
  
   }
  </code></pre>
  
  <p>READING:</p>
  
  <p><a href="https://stackoverflow.com/questions/5662923/asp-net-mvc3-custom-validation-attribute-client-side-broken">ASP.NET MVC3 - Custom validation attribute -&gt; Client-side broken</a></p>