ASP.NET MVC验证机制详解

ASP.NET MVC框架提供了强大的验证机制,它不仅支持服务器端和客户端验证,而且能够隐藏所有验证细节,使得控制器代码和HTML标记非常干净。本文将详细介绍ASP.NET MVC中的验证机制,包括如何使用模型类中的验证属性,以及服务器端和客户端验证的实现方式。

验证属性在模型类中的应用

要体验ASP.NET MVC的验证特性,最简单的方法是创建一个使用默认的Internet应用程序模板的Web应用程序,它会自动生成所有必要的验证代码。

RegisterModel类为例,可以看到生成的验证代码:

public class RegisterModel { [Required] [Display(Name = "用户名")] public string UserName { get; set; } [Required] [DataType(DataType.EmailAddress)] [Display(Name = "电子邮件地址")] public string Email { get; set; } [Required] [ValidatePasswordLength] [DataType(DataType.Password)] [Display(Name = "密码")] public string Password { get; set; } [DataType(DataType.Password)] [Display(Name = "确认密码")] [Compare("Password", ErrorMessage = "密码和确认密码不匹配。")] public string ConfirmPassword { get; set; } }

在上述代码中,Required属性用于标记UserNameEmailPassword属性为必填项。Display属性用于为所有属性提供显示名称,作为字段标签或错误消息。DataType属性用于指示属性的类型。ValidatePasswordLength是一个自定义验证属性,稍后将详细介绍。Compare属性用于比较PasswordConfirmPassword

验证属性的来源

通用验证属性定义在System.ComponentModel.DataAnnotations命名空间(System.ComponentModel.DataAnnotations.dll)中。这包括Required属性、Range属性、RegularExpression属性、StringLength属性等。它们都继承自ValidationAttribute基类,并重写IsValid方法以提供特定的验证逻辑。

DisplayAttribute也在System.ComponentModel.DataAnnotations命名空间中,但它是一个显示属性,而不是验证属性。DataTypeAttribute是一个验证属性,但在MSDN中被归类为显示属性。

System.ComponentModel.DataAnnotations命名空间中,还有一些为Entity Framework设计的数据处理属性,如AssociationAttributeKeyAttribute等。

CompareAttribute是ASP.NET MVC提供的专用验证属性,位于System.Web.Mvc命名空间(System.Web.Mvc.dll)。ASP.NET MVC还提供了另一个验证属性RemoteAttribute,它使用Ajax调用来执行服务器端控制器操作的验证。CompareAttribute还实现了IClientValidatable接口,这是ASP.NET MVC客户端验证的接口。IClientValidatable只有一个方法GetClientValidationRule,其签名如下:

IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context);

ModelMetadata是一个通用元数据的容器,它允许类在进行验证时使用模型信息。ControllerContext是一个包含HTTP请求和其他请求环境数据的容器。ModelClientValidationRule是客户端验证规则的基类,它被发送到浏览器。MVC中有六种内置验证规则:

  • ModelClientValidationEqualToRule
  • ModelClientValidationRemoteRule
  • ModelClientValidationRequiredRule
  • ModelClientValidationRangeRule
  • ModelClientValidationStringLengthRule
  • ModelClientValidationRegexRule

如果仔细观察,会发现System.ComponentModel.DataAnnotations中的所有通用验证属性在这里都有一个对应的ModelClientValidationRule。ASP.NET MVC创建了适配器,例如RequiredAttributeAdapter,以扩展通用验证属性以支持ASP.NET MVC验证设计。

ValidatePasswordLengthAttribute是一个自定义验证,继承自ValidationAttribute并实现了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) }; } }

需要注意的是,ValidatePasswordLengthAttribute引用了Membership,因此应用程序需要有Membership提供程序的配置才能使其工作。

服务器端验证

为了看到自定义验证如何在ASP.NET MVC服务器端发挥作用,让来看一下调用自定义验证属性ValidatePasswordLengthAttributeIsValid方法的调用栈。

从调用栈中,可以看到服务器端验证是在模型绑定步骤(DefaultModelBinder.BindModel(…))中进行的。ModelValidator调用每个验证属性类来验证模型数据,基于给定的设置。验证结果(ModelValidationResult)存储在ModelState中,以在操作或视图中使用。

[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); }

ModelState.IsValid从检查内部错误集合返回truefalse

public bool IsValid { get { return this.Values.All((ModelState modelState) => modelState.Errors.Count == 0); } }

客户端验证

客户端验证web.config中默认启用。

<appSettings> <add key="ClientValidationEnabled" value="true"/> <add key="UnobtrusiveJavaScriptEnabled" value="true"/> </appSettings>

但是,必须确保在视图页面中也添加了jquery.validation.min.jsjquery.validate.unobtrusive.min.js

<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>

需要HtmlHelper类的扩展方法进行验证:

  • Validate
  • ValidateFor
  • ValidationMessage
  • ValidationMessageFor
  • ValidationSummary

jquery.validate.min.js是标准的jQuery验证库。jquery.validate.unobtrusive.min.js是ASP.NET MVC客户端验证库,它建立在jQuery验证库之上。它使用HTML元素属性来存储验证信息。这种设计非常干净,对UI设计师来说非常友好。

远程验证属性在行动

上面的验证代码是从ASP.NET MVC项目模板生成的。还想在这里展示Remote验证属性,以展示如何使用它。要求非常简单——应用程序不允许用户名为"Bin",应用程序需要在用户在用户名文本框中输入"Bin"后立即显示错误。

LogOnModelUserName上添加Remote属性。

[Required] [Display(Name = "用户名")] [Remote("DisallowName", "Account")] public string UserName { get; set; }

第一个参数是Action名称,第二个参数是Controller名称。

AccountController中创建一个DisallowName操作。

public ActionResult DisallowName(string UserName) { if (UserName != "Bin") { return Json(true, JsonRequestBehavior.AllowGet); } return Json(string.Format("{0} is invalid", UserName), JsonRequestBehavior.AllowGet); }

就是这样。远程验证完成了。让看看在屏幕上是什么样子的:

ASP.NET MVC3中的验证设计非常干净且功能强大。它使得服务器端和客户端验证保持一致。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485