I love ASP.NET MVC 2 validations for client and server via annotations. Steve Sanderson's xVal is great too, but in this post I want to focus on a custom validation for MVC 2 which is frustratingly missing from the out-of-the-box validations. There is a very nice StringLengthAttribute which allows you to specify a maximum length but does not provide for a minimum length.
At first I attacked this deficiency with a regex like this:
[RegularExpression("[\\S]{6,}", ErrorMessage = "Must be at least 6 characters.")] public string Password { get; set; }
This approach just seems clunky. Happily, while reading Scott Allen's piece on MVC 2 validation in MSDN magazine, I came across a critical reference to one of Phil Haack's blog posts which I must have overlooked.
Thanks go to Phil's easy to follow instructions on writing a custom validator for MVC 2 that will work on both client and server sides.
So here's my custom MinStringLengthAttribute and supporting code which let's me do something easier and cleaner like this:
[StringLength(128, ErrorMessage = "Must be under 128 characters.")] [MinStringLength(3, ErrorMessage = "Must be at least 3 characters.")] public string PasswordAnswer { get; set; }
If you really wanted to get creative, you could produce a combination of the two, but I'll leave that for another day.
Here's the code for the attribute and the required validator:
public class MinStringLengthAttribute : ValidationAttribute { public int MinLength { get; set; } public MinStringLengthAttribute(int minLength) { MinLength = minLength; } public override bool IsValid(object value) { if (null == value) return true; //not a required validator var len = value.ToString().Length; if (len < MinLength) return false; else return true; } } public class MinStringLengthValidator : DataAnnotationsModelValidator<MinStringLengthAttribute> { int minLength; string message; public MinStringLengthValidator(ModelMetadata metadata, ControllerContext context, MinStringLengthAttribute attribute) : base(metadata, context, attribute) { minLength = attribute.MinLength; message = attribute.ErrorMessage; } public override IEnumerable<ModelClientValidationRule> GetClientValidationRules() { var rule = new ModelClientValidationRule { ErrorMessage = message, ValidationType = "minlen" }; rule.ValidationParameters.Add("min", minLength); return new[] { rule }; } }
Here's the code in the Global.asax.cs that registers the validator:
protected void Application_Start() { RegisterRoutes(RouteTable.Routes); DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(MinStringLengthAttribute), typeof(MinStringLengthValidator)); }
Here's the javascript to hook up the client side:
Sys.Mvc.ValidatorRegistry.validators["minlen"] = function(rule) { //initialization var minLen = rule.ValidationParameters["min"]; //return validator function return function(value, context) { if (value.length < minLen) return rule.ErrorMessage; else return true; /* success */ }; };
Now, in your view, add <% Html.EnableClientValidation(); %> and that's all there is to it.
Page rendered at Tuesday, February 07, 2012 6:24:42 AM (Mountain Standard Time, UTC-07:00)
DisclaimerThe opinions expressed herein are just that, opinions. Don't have a fit if you think they're wrong. Post your comment or write your own blog.