本文體驗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的驗證作擴充套件是為了演示。