Asp.net MVC驗證那些事(4)-- 自定義驗證特性


在項目的實際使用中,MVC默認提供的Validation Attribute往往不夠用,難以應付現實中復雜多變的驗證需求。比如, 在注冊用戶的過程中,往往需要用戶勾選”免責聲明”,這個checkbox往往是必填項,但是MVC中並沒有提供對於checkbox必選的驗證。這篇文章通過解決checkbox必選驗證的問題,看看如何在MVC中定義自己的自定義驗證屬性。

閱讀目錄:

一. CheckBox必選驗證的困局

二. 對於服務端ValidationAttribute的實現分析

三. 自定義EnforceTrueAttribute實現服務器端驗證

四. 添加客戶端驗證

五. 總結

一, CheckBox必選驗證的困局

先來引入問題,下面是我們定義的RegisterModel, 為了簡化問題,只是定義了2個屬性

public class RegisterModel 
  { 
     [DisplayName("User Name")] 
     [Required(ErrorMessage = "User Name is required")] 
     public String UserName { get; set; }

     [Required] 
     public bool IsAgreeTerm { get; set; }

}

我們嘗試在IsAgreeTerm添加上[Required], 希望能夠幫我們實現必選驗證。

注冊View頁面的代碼如下:

@using (Html.BeginForm()) { 
    @Html.AntiForgeryToken() 
    @Html.ValidationSummary()

    <fieldset> 
        <legend>Registration Form</legend> 
        <ol> 
            <li> 
                @Html.LabelFor(m => m.EmployeeName) 
                @Html.EditorFor(m => m.EmployeeName) 
                <br/> 
                @Html.ValidationMessageFor(m => m.EmployeeName) 
            </li> 
             <li> 
                @Html.LabelFor(m => m.IsAgreeTerm) 
                @Html.EditorFor(m => m.IsAgreeTerm) 
                <br/> 
                @Html.ValidationMessageFor(m => m.IsAgreeTerm) 
            </li> 
      </ol> 
        <input type="submit" value="Register" /> 
    </fieldset> 
}

接下來看看實際的運行效果:

驗證中只是提示了User Name必填,而沒有提示IsAgreeTerm。 這是因為checkbox不選的話,提交到后台的值是false, 也就是說無論如何checkbox都是有值的,[Required]驗證Attribute並不能按照預想的那樣為我們解決驗證問題。

下面我們就着手實現自己的ValidationAttribute來實現該驗證。

二, 對於服務端ValidationAttribute的實現分析

在實現自己的ValidationAttribute之前,我們來分析一下MVC中提供的RequiredAttribute

blog-requireattribute-code

上面能夠看出, RequiredAttribute繼承於ValidationAttribute抽象類, 覆蓋了IsValid方法.

也就是說, RequiredAttribute提供了方法,用來判斷添加RequiredAttribute驗證規則的屬性是否valid的標准。

實際上MVC的服務端驗證流程是這樣的:

客戶端請求—>Route解析—> model綁定—> 數據驗證.

現在思路應該比較清晰,就是同樣繼承ValidationAttribute, 實現我們的CheckboxRequiredAttribute.

三, 自定義EnforceTrueAttribute實現服務器端驗證

這里我們定義個EnforceTrueAttribute繼承ValidationAttribute

public class EnforceTrueAttribute : ValidationAttribute 
   { 
       public override bool IsValid(object value) 
       { 
           if (value == null) return false; 
           if (value.GetType() != typeof(bool)) throw new InvalidOperationException("can only be used on boolean properties."); 
           return (bool)value; 
       }

       public override string FormatErrorMessage(string name) 
       { 
           return "The " + name + " field must be checked in order to continue."; 
       }

   }

這里覆蓋了父類的2個方法IsValid和FormatErrorMessage。

在IsValid方法中,如果提交的checkbox的值不是true, 驗證就會不通過。
FormatErrorMessage方法,是根據字段的名稱顯示錯誤信息.

在IsAgreeTerm上應用上EnforceTrueAttribute.

[DisplayName("Term")] 
[EnforceTrue] 
public bool IsAgreeTerm { get; set; }

編譯運行,提交表單之后的效果是這樣的:

blog2-cnblogs.com 

四, 添加客戶端驗證

我們不僅僅希望服務端驗證,也同時想加上客戶端驗證。

4.1 在EnforceTrueAttribute上實現IClientValidatable

要實現客戶端驗證,首先需要在服務端的EnforceTrueAttribute上實現IClientValidatable

public class EnforceTrueAttribute : ValidationAttribute, IClientValidatable 
{ 
    public override bool IsValid(object value) 
    { 
        if (value == null) return false; 
        if (value.GetType() != typeof(bool)) throw new InvalidOperationException("can only be used on boolean properties."); 
        return (bool)value; 
    }

    public override string FormatErrorMessage(string name) 
    { 
        return "The " + name + " field must be checked in order to continue."; 
    }

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context) 
    { 
        yield return new ModelClientValidationRule 
        { 
            ErrorMessage = String.IsNullOrEmpty(ErrorMessage) ? FormatErrorMessage(metadata.DisplayName) : ErrorMessage, 
            ValidationType = "enforcetrue" 
        }; 
    } 
}

上面代碼中,我們實現了IClientValidatable接口的方法GetClientValidationRules, 該方法返回了ModelClientValidationRule,包含了的信息ValidationType 和ErrorMessage.

對比一下,在EnforceTrueAttribute在實現IClientValidatable接口前后,生成前段的html差別,就能知道改方法的作用了.

blog-mvc-validation

4.2 擴展客戶端驗證方法

通過實現IClientValidatable接口,我們只是做到了給應用了該標簽的input, 在生成html代碼時候,添加上了額外的驗證規則,但是這些規則在客戶端上,還沒有方法來驗證。下面就是擴展客戶端驗證框架unobtrusive來實現完整的客戶端驗證流程。

<script type="text/javascript"> 
      jQuery.validator.addMethod("enforcetrue", function(value, element, param) { 
          return element.checked; 
      }); 
      jQuery.validator.unobtrusive.adapters.addBool("enforcetrue"); 
  </script>

五, 總結

到這里,對於完成添加一個自定義驗證需要完成的流程應該是比較清楚了。

1. 服務端創建ValidationAttribute繼承ValidationAttribute, 實現服務端的驗證
2. ValidationAttribute繼承IClientValidatable接口為生成的input標記客戶端驗證規則,同時客戶端擴展驗證方法

在實際開發中,擴展驗證規則來達到數據驗證的目的,能夠達到代碼復用的效果,同時也使得數據驗證變得更加簡單和方便。

相關系列文章: 

Asp.net MVC驗證那些事(1)-- 介紹和驗證規則使用
Asp.net MVC驗證哪些事(2)-- 驗證規則總結以及使用
Asp.net MVC驗證哪些事(3)-- Remote驗證及其改進(附源碼)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM