ASP.NET MVC3 验证基础
在本文中,我将简要解释 ASP.NET MVC3 的验证是如何工作的。
引言
ASP.NET MVC3 附带了一个验证功能,它不仅支持服务器端和客户端验证,还隐藏了所有验证细节,从而实现了非常整洁的控制器代码和 HTML 标记。
验证演练
尝试 ASP.NET MVC 验证功能的最简单方法是创建一个具有默认 Internet 应用程序模板的 Web 应用程序,该模板将自动生成所有必需的验证代码。
模型类上的验证属性
让我们看看为 RegisterModel
类生成的验证代码。
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; }
}
Required
属性用于UserName
、Email
和Password
属性,将它们标记为必填项。Display
属性用于所有属性,为它们提供显示名称,用作字段标签或错误消息。DataType
属性用于Email
和Password
属性,以指示属性的类型。ValidationPasswordLength
属性是一个自定义验证属性。我稍后会详细讨论它。Compare
属性用于ConfirmPassword
,以比较Password
和ConfirmPassword
。
验证属性来自哪里?
通用验证属性定义在 System.ComponentModel.DataAnnotations
命名空间(System.ComponentModel.DataAnnotations.dll)中。这包括 Required
属性、Range
属性、RegularExpression
属性、StringLength
属性等。它们都继承自 ValidationAttribute
基类,并重写 IsValid
方法以提供其特定的验证逻辑。DisplayAttribute
也位于 System.ComponentMode.DataAnnotations
命名空间中,但它是显示属性而不是验证属性。DataTypeAttribute
是一个验证属性,但在 MSDN 中被归类为显示属性。供参考,在 System.ComponentMode.DataAnnotations
命名空间中,有用于 Entity Framework 的数据建模属性,如 AssociationAttribute
、KeyAttribute
等。

CompareAttribute
是 ASP.NET MVC 提供的特殊用途验证属性。它位于 System.Web.Mvc
命名空间(System.Web.Mvc.dll)中。ASP.NET MVC 提供的另一个验证属性是 RemoteAttribute
,它使用 Ajax 调用服务器端控制器操作来执行验证。CompareAttribute
还实现了 ASP.NET MVC 客户端验证的接口 IClientValidatable
。IClientValidatable
只有一个方法 GetClientValidationRule
,其签名如下:
IEnumerable<modelclientvalidationrule> GetClientValidationRules
(ModelMetadata metadata, ControllerContext context);
</modelclientvalidationrule>
ModelMetadata
是通用元数据的容器。它允许类在进行验证时利用模型信息。ControllerContext
是 HTTP 请求和其他请求环境数据的容器。ModelClientValidationRule
是发送到浏览器的客户端验证规则的基类。MVC 中有六个内置验证规则:ModelClientValidationEqualToRule
、ModelClientValidationRemoteRule
、ModelClientValidationRequiredRule
、ModelClientValidationRangeRule
、ModelClientValidationStringLengthRule
、ModelClientValidationRegexRule
。如果你留意一下,你会发现System.ComponentModel.DataAnnotations
中的所有通用验证属性都有一个对应的ModelClientValidationRule
。ASP.NET MVC 创建适配器,例如RequiredAttributeAdapter
,来扩展通用验证属性以支持 ASP.NET MVC 验证设计。

ValidatePasswordLengthAttribute
是一个自定义验证,它继承自 ValidateAttribute
并实现了 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>
这里需要注意的一点是 ValidatePasswordLengthAttribute
引用了 Membership
,因此应用程序需要配置 Membership
提供程序才能使其正常工作。

您可以在单个属性上应用不同的验证属性,这种聚合设计使得 ASP.NET MVC 的验证功能更加强大和灵活。
Server Side Validation
为了了解我们的自定义验证在 ASP.NET MVC 服务器端是如何发挥作用的,让我们看一下调用自定义验证属性 ValidatePasswordLengthAttribute
的 IsValid
方法的调用堆栈。

从调用堆栈可以看出,服务器端验证发生在模型绑定阶段(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
通过检查内部错误集合返回 true
或 false
。
public bool IsValid
{
get
{
return this.Values.All((ModelState modelState) => modelState.Errors.Count == 0);
}
}
Client Side Validation
客户端验证在 web.config 中默认启用。
<appSettings>
<add key="ClientValidationEnabled" value="true"/>
<add key="UnobtrusiveJavaScriptEnabled" value="true"/>
</appSettings>
但是,您必须确保 jquery.validation.min.js 和 jquery.validation.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 项目模板生成的。我还想在这里展示远程验证属性,以说明如何使用它。要求很简单——用户名“Bin”在此应用程序中不允许,应用程序需要在用户名字段中输入“Bin”后立即显示错误。
- 在
LogOnModel
的UserName
属性上添加 Remote 属性。[Required] [Display(Name = "User 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 中的验证设计非常整洁且功能强大。它使服务器端和客户端验证保持一致。
Using the Code
代码是在 Visual Studio 2010 中开发的。使用代码没有特殊要求。
历史
- 2011 年 9 月 4 日:初稿