本文体验MVC自定义验证特性,来实现对邮件的验证。对于刚写完的自定义验证特性,起初只能支持后端验证。如果要让前端jquery支持,还必须对jquery的验证进行扩展。
本文与"MVC验证01-基础、远程验证"相关,如有需要,请参考。
当我们验证有关Email属性的时候,我们可能这样写:
[RegularExpression(@"\w.+\@\w.+")]
public string Email { get; set; }
这仅仅考虑了@符号,但这还不够,我们又可能这样写:
[RegularExpression(@"^[\w-]+(\.[\w-]+)*@([\w-]+\.)+[a-zA-Z]+$")]
public string Email { get; set; }
这样略显"臃肿",实际上,我们可以扩展MVC的ValidateAttribute特性,做到“一次封装,多次使用”。
自定义验证特性
![]()
using System.ComponentModel.DataAnnotations;
using System.Text.RegularExpressions;
namespace MvcValidation.Extension
{
public sealed class EmailAttribute : ValidationAttribute
{
public const string reg = @"
^[\w-]+(\.[\w-]+)*@([\w-]+\.)+[a-zA-Z]+$";
public EmailAttribute()
{
}
//重写基类方法
public override bool IsValid(
object value)
{
if (
value ==
null)
return true;
if (
value is string)
{
Regex regEx =
new Regex(reg);
return regEx.IsMatch(
value.ToString());
}
return false;
}
}
}
注意:
把自定义扩展类声明为sealed class。
此处验证邮件的正则表达式不见得是最完美的。
自定义特性的用武之地:View model
![]()
using MvcValidation.Extension;
public class RegisterModel
{
[Required]
[StringLength(6, MinimumLength = 2)]
//加
[Display(Name = "
用户名")]
[Remote("
CheckUserName","
Validate", ErrorMessage = "
远程验证用户名失败")]
public string UserName {
get;
set; }
[Required]
[DataType(DataType.EmailAddress)]
[Display(Name = "
邮件")]
[Email]
public string Email {
get;
set; }
[Required]
[StringLength(100, ErrorMessage = "
{0}栏位最少{2}个字,最多{1}个字", MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "
密码")]
public string Password {
get;
set; }
[DataType(DataType.Password)]
[Display(Name = "
确认密码")]
[System.ComponentModel.DataAnnotations.Compare("
Password", ErrorMessage = "
密码和确认密码不匹配。")]
public string ConfirmPassword {
get;
set; }
}
Register.cshtml
![]()
@model MvcValidation.Models.RegisterModel
@{
ViewBag.Title = "
注册";
}
<hgroup
class="
title">
<h1>@ViewBag.Title.</h1>
<h2>创建新帐户。</h2>
</hgroup>
@
using (Html.BeginForm()) {
@Html.AntiForgeryToken()
@Html.ValidationSummary()
<fieldset>
<legend>注册表单</legend>
<ol>
<li>
@Html.LabelFor(m => m.UserName)
@Html.TextBoxFor(m => m.UserName)
</li>
<li>
@Html.LabelFor(m => m.Email)
@Html.TextBoxFor(m => m.Email)
</li>
<li>
@Html.LabelFor(m => m.Password)
@Html.PasswordFor(m => m.Password)
</li>
<li>
@Html.LabelFor(m => m.ConfirmPassword)
@Html.PasswordFor(m => m.ConfirmPassword)
</li>
</ol>
<input type="
submit"
value="
注册" />
</fieldset>
}
@section Scripts {
@Scripts.Render("
~/bundles/jqueryval")
}
效果:

注意:
此时的自定义的验证特性只支持后端验证,如果想支持前端jquery验证,需要实现 IClientValidatable接口。
自定义特性实现IClientValidatable接口,为实现jquery验证做准备
![]()
using System.ComponentModel.DataAnnotations;
using System.Text.RegularExpressions;
using System.Web.Mvc;
namespace MvcValidation.Extension
{
public sealed class EmailAttribute : ValidationAttribute, IClientValidatable
{
public const string reg = @"
^[\w-]+(\.[\w-]+)*@([\w-]+\.)+[a-zA-Z]+$";
public EmailAttribute()
{
}
//重写基类方法
public override bool IsValid(
object value)
{
if (
value ==
null)
return true;
if (
value is string)
{
Regex regEx =
new Regex(reg);
return regEx.IsMatch(
value.ToString());
}
return false;
}
public System.Collections.Generic.IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
ModelClientValidationRule rule =
new ModelClientValidationRule
{
ValidationType = "
email",
ErrorMessage = FormatErrorMessage(metadata.GetDisplayName())
};
yield
return rule;
}
}
}
注意:
ValidationType属性的值一定要小写,否则报错。
扩展jquery以支持自定义扩展特性EmailAttribute
jQuery.validator.email.js文件:
//扩展方法
$.validator.addMethod("email", function (value, element) {
if (value == false) {
return true;
}
this.optional(element) || /^[\w-]+(\.[\w-]+)*@([\w-]+\.)+[a-zA-Z]+$/i.test(value);
});
//扩展方法注册
$.validator.unobtrusive.adapters.addBool("email");
为了实现jquery客户端验证,Register.cshtml中必须的js文件包括:
1、引用query-{version}.js
2、引用jquery.validate.js
3、引用jquery.validate.unobtrusive.js
4、自定义的jquery验证扩展
由于在_Layout.cshtml中有@Scripts.Render("~/bundles/jquery"),所有Register.cshtml中不需要引用了。
Register.cshtml中包含@Scripts.Render("~/bundles/jqueryval"),意味着包含了对2和3的引用。
Register.cshtml中还需要引入jquery针对自定义特性EmailAttribute特性的扩展方法。
完整Register.cshtml中如下:
![]()
@model MvcValidation.Models.RegisterModel
@{
ViewBag.Title = "
注册";
}
<hgroup
class="
title">
<h1>@ViewBag.Title.</h1>
<h2>创建新帐户。</h2>
</hgroup>
@
using (Html.BeginForm()) {
@Html.AntiForgeryToken()
@Html.ValidationSummary()
<fieldset>
<legend>注册表单</legend>
<ol>
<li>
@Html.LabelFor(m => m.UserName)
@Html.TextBoxFor(m => m.UserName)
</li>
<li>
@Html.LabelFor(m => m.Email)
@Html.TextBoxFor(m => m.Email)
</li>
<li>
@Html.LabelFor(m => m.Password)
@Html.PasswordFor(m => m.Password)
</li>
<li>
@Html.LabelFor(m => m.ConfirmPassword)
@Html.PasswordFor(m => m.ConfirmPassword)
</li>
</ol>
<input type="
submit"
value="
注册" />
</fieldset>
}
@section Scripts {
@Scripts.Render("
~/bundles/jqueryval")
<script src="
~/Scripts/jQuery.validator.email.js"></script>
}
效果:

如何确认已经启用了jquery的验证机制呢?
在没有实现IClientValidatable之前,审查Email的表单元素,如下:

当实现IClientValidatable之后,审查Email的表单元素,如下:

可见,实现IClientValidatable之后,多了data-val-email属性。
注意:
jQuery中本身包含了对Email的验证,这里对jquery的验证作扩展是为了演示。