Introduction
The ASP.NET MVC3 comes with a validation feature that not only supports both server side and client side validation, but also hides all validation details to have a very clean controller code and HTML markup.
Validation Walkthrough
The easiest way to try ASP.NET MVC validation feature is to create a web application with the default internet application template that will automatically generate all essential validation code in it.
Validation Attribute on Model Class
Let’s take a look at the validation code generated for
RegisterModel class.public class RegisterModel
{
[Required]
[Display(Name = "User name")]
public string UserName { get; set; }
[Required]
[DataType(DataType.EmailAddress)]
[Display(Name = "Email address")]
public string Email { get; set; }
[Required]
[ValidatePasswordLength]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
[DataType(DataType.Password)]
[Display(Name = "Confirm password")]
[Compare("Password", ErrorMessage = "The password and confirmation password
do not match.")]
public string ConfirmPassword { get; set; }
}- The
Requiredattribute is used on propertyUserName,EmailandPasswordto mark them as required. - The
Displayattribute is used on all properties to give them a display name as field label or in error message. - The
DataTypeattribute is used on propertyEmailandPasswordto indicate type of property. - The
ValidationPasswordLengthattribute is a custom validation attribute. I will talk more about it later. - The
Compareattribute is used onConfirmPasswordto comparePasswordwithConfirmPassword.
Where is Validation Attribute from?
The general purpose validation attributes are defined in
System.ComponentModel.DataAnnotations namespace (System.ComponentModel.DataAnnotations.dll). This includes Required attribute, Range attribute,RegularExpression attribute, StringLength attribute, etc. They all inherit from ValidationAttributebase class and override IsValid method to provide their specific validation logic. DisplayAttribute is also inSystem.ComponentMode.DataAnnotations namespace, but it’s a display attribute instead of validation attribute. DataTypeAttribute is a validation attribute, but is classified as display attribute in MSDN. FYI, inSystem.ComponentMode.DataAnnotations namespace, there are Data Modeling attributes,AssociationAttribute, KeyAttribute, etc. designed for Entity Framework.
CompareAttribute is a special purpose validation attribute provided by ASP.NET MVC. It is in System.Web.Mvcnamespace (System.Web.Mvc.dll). Another validation attribute provided by ASP.NET MVC is RemoteAttribute that uses Ajax call to service side controller action to do validation. The CompareAttribute also implementsIClientValidatable, an interface of ASP.NET MVC client validation. The IClientValidatable has only one method GetClientValidationRule that has the following signature:IEnumerable<modelclientvalidationrule> GetClientValidationRules
(ModelMetadata metadata, ControllerContext context);
</modelclientvalidationrule>ModelMetadatais a container for common metadata. It allows classes to utilize model information when doing validationControllerContextis a container for HTTP request and other request environment data.ModelClientValidationRuleis a base class for client validation rule that is sent to the browser. There are six built-in validation rules in MVC:ModelClientValidationEqualToRule,ModelClientValidationRemoteRule,ModelClientValidationRequiredRule,ModelClientValidationRangeRule,ModelClientValidationStringLengthRule,ModelClientValidationRegexRule. If you pay attention, you can see all general purpose validation attributes inSystem.ComponentModel.DataAnnotationshave a correspondingModelClientValidationRulein here. The ASP.NET MVC creates adapter, e.g.RequiredAttributeAdapter, to extend general purpose validation attribute to support ASP.NET MVC validation design.

ValidatePasswordLengthAttribute is a custom validation that inherits from ValidateAttribute and implements IClientValidatable.[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property,
AllowMultiple = false, Inherited = true)]
public sealed class ValidatePasswordLengthAttribute : ValidationAttribute,
IClientValidatable
{
private const string _defaultErrorMessage = "'{0}'
must be at least {1} characters long.";
private readonly int _minCharacters =
Membership.Provider.MinRequiredPasswordLength;
public ValidatePasswordLengthAttribute()
: base(_defaultErrorMessage)
{
}
public override string FormatErrorMessage(string name)
{
return String.Format(CultureInfo.CurrentCulture, ErrorMessageString,
name, _minCharacters);
}
public override bool IsValid(object value)
{
string valueAsString = value as string;
return (valueAsString != null && valueAsString.Length >= _minCharacters);
}
public IEnumerable<modelclientvalidationrule>
GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
return new[]{
new ModelClientValidationStringLengthRule(FormatErrorMessage
(metadata.GetDisplayName()), _minCharacters, int.MaxValue)
};
}
}
</modelclientvalidationrule>One note in here is the
ValidatePasswordLengthAttribute has reference to Membership, so the application needs to have configuration of Membership provider in place to make it work.
You can apply different validation attributes on a single property, this aggregate design makes ASP.NET MVC validation feature more powerful and flexible.
Server Side Validation
In order to see how our custom validation comes into play in ASP.NET MVC server side, let’s take a look at the call stack to
IsValid method of custom validation attribute - ValidatePasswordLengthAttribute.
From the call stack, you can see the server side validating is happening during model binding step (
DefaultModelBinder.BindModel(…)). The ModelValidator calls each validation attribute class to validate the model data based on a given setting. The validation results (ModelValidationResult) are stored inModelState to be used in action or view.[HttpPost]
public ActionResult Register(RegisterModel model)
{
if (ModelState.IsValid)
{
// Attempt to register the user
MembershipCreateStatus createStatus = MembershipService.CreateUser
(model.UserName, model.Password, model.Email);
if (createStatus == MembershipCreateStatus.Success)
{
FormsService.SignIn(model.UserName, false /* createPersistentCookie */);
return RedirectToAction("Index", "Home");
}
else
{
ModelState.AddModelError("",
AccountValidation.ErrorCodeToString(createStatus));
}
}
// If we got this far, something failed, redisplay form
ViewBag.PasswordLength = MembershipService.MinPasswordLength;
return View(model);
}The
ModelState.IsValid returns true or false from checking internal errors collection.public bool IsValid
{
get
{
return this.Values.All((ModelState modelState) => modelState.Errors.Count == 0);
}
}Client Side Validation
The client side validation is enabled by default in web.config.
<appSettings>
<add key="ClientValidationEnabled" value="true"/>
<add key="UnobtrusiveJavaScriptEnabled" value="true"/>
</appSettings>However, you must make sure jquery.validation.min.js and jquery.validation.unobtrusive.min.js are added in the view page also.
<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript">
</script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")"
type="text/javascript"></script>The extension methods for
HtmlHelper class are required for validation: Validate, ValidateFor,ValidationMessage, ValidationMessageFor, ValidationSummary.The jquery.validate.min.js is standard jQuery validation library. The jquery.validate.unobtrusive.min.js is an ASP.NET MVC client side validation library that is built on top of jQuery validation library. It uses HTML element attributes to store validation information. This design is very clean and intrusive to the UI designer.
Remote Validation Attribute in Action
The above validation code is generated from ASP.NET MVC project template. I also want to show Remote Validation Attribute here to show how to use it. The requirement is very simple - UserName “Bin” is not allow in the application, the application needs to show error right after entered “Bin” in User Name textbox.
- Add Remote attribute on
UserNameofLogOnModel.[Required] [Display(Name = "User name")] [Remote("DisallowName", "Account")] public string UserName { get; set; }
The first parameter isActionname, the second parameter isControllername. - Create a
DisallowNameaction inAccountController.public ActionResult DisallowName(string UserName) { if (UserName != "Bin") { return Json(true, JsonRequestBehavior.AllowGet); } return Json(string.Format("{0} is invalid", UserName), JsonRequestBehavior.AllowGet); }
That is, a remote validation is done. Let’s take a look at what it looks like on screen:
Conclusion
The validation design in ASP.NET MVC3 is very clean and powerful. It makes server and client side validation consistent.
Using the Code
The code is developed in Visual Studio 2010. There is no special requirement for using the code.
No comments:
Post a Comment