Asp.Net MVC Model Validation:Custom Validation – 以 Required If 為例

在前篇「Asp.Net MVC Model Validation:Remote validation」的介紹之下,想必大家對於 .Net MVC 的 Model Validation 運作機制都有一定程度的了解,接下來將進一步介紹如何在 .Net MVC Model Validation 的運作機制加上自訂驗證規則(前、後端,使我們專案的表單驗證機制更加完善

自訂驗證規則的實作要素分為後端前端,以下將以 RequiredIf 的使用情境來說明:

後端

  • 自訂一個 Validation Attribute 類別(RequiredIfAttribute.cs),並:
    1. 繼承 ValidationAttribute 類別後覆寫 IsValid 方法來加入自訂驗證規則:後端 ModelState.IsValid 所觸發的驗證方法。
    2. 繼承 IClientValidatable 類別後實作 GetClientValidationRules 方法:當 .Net MVC framework 運作時,會透過此 interface 找到有實作的類別來取得 validation object,再透過 GetClientValidationRules 檢索及發送相關的 metadata 或 rules 至前端。(貼心小叮嚀:要提供前端驗證時,一定要實作此步驟)
public class RequiredIfAttribute : ValidationAttribute, IClientValidatable
{
	private String PropertyName { get; set; }
	private Object DesiredValue { get; set; }
	private readonly RequiredAttribute _innerAttribute;

	public RequiredIfAttribute(String propertyName, Object desiredvalue)
	{
		PropertyName = propertyName;
		DesiredValue = desiredvalue;
		_innerAttribute = new RequiredAttribute();
	}

	protected override ValidationResult IsValid(object value, ValidationContext validationContext)
	{
		var dependentValue = validationContext.ObjectInstance.GetType().GetProperty(PropertyName).GetValue(validationContext.ObjectInstance, null);
		if (dependentValue != null && dependentValue.ToString() == DesiredValue.ToString() && !_innerAttribute.IsValid(value))
		{
			return new ValidationResult(FormatErrorMessage(validationContext.DisplayName), new[] { validationContext.MemberName });
		}
		return ValidationResult.Success;
	}

	public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
	{
		var rule = new ModelClientValidationRule
		{
			ErrorMessage = string.Format("{0} 欄位是必要項。", metadata.GetDisplayName()),
			ValidationType = "requiredif",
		};
		rule.ValidationParameters["dependentproperty"] = PropertyName;
		rule.ValidationParameters["desiredvalue"] = DesiredValue is bool ? DesiredValue.ToString().ToLowerInvariant() : DesiredValue;
		yield return rule;
	}
}

前端 

  • 建立一個 JS 檔案(jquery.requiredIfValidator.js),並:
    1. 透過 $.validator.unobtrusive.adapters.add 來定義自訂驗證規則的 Html 語法及額外(含參數)的設定程序。
    2. 透過 $.validator.addMethod 加入自訂驗證規則:為前端 $(‘form’).valid() 所觸發的驗證方法。(貼心小叮嚀:如果僅需實作純前端驗證,實作此步驟即可完成)
// 將 Html 相關語法及參數的設定透過 unobtrusive adapters 新增進 jQuery validator
$.validator.unobtrusive.adapters.add('requiredif', ['dependentproperty', 'desiredvalue'], function (options) {
    options.rules['requiredif'] = options.params;
    options.messages['requiredif'] = options.message;
});

$(document).ready(function () {

    // 註冊 jQuery validator 的 requiredif 自訂規則驗證方法
    $.validator.addMethod('requiredif', function (value, element, parameters) {
        var desiredvalue = parameters.desiredvalue;
        desiredvalue = (desiredvalue == null ? '' : desiredvalue).toString();
        var controlType = $("input[name$='" + parameters.dependentproperty + "']").attr("type");
        var actualvalue = {}
        if (controlType == "checkbox" || controlType == "radio") {
            var control = $("input[name$='" + parameters.dependentproperty + "']:checked");
            actualvalue = control.val();
        } else {
            actualvalue = $("#" + parameters.dependentproperty).val();
        }
        if ($.trim(desiredvalue).toLowerCase() === $.trim(actualvalue).toLocaleLowerCase()) {
            var isValid = $.validator.methods.required.call(this, value, element, parameters);
            return isValid;
        }
        return true;
    });

});

結果展示(DEMO)

將 Model 中需要驗證的 Property 掛上 DataAnnotation:RequiredIf 即完成設定與實作:


希望透過以上的介紹,
對大家往後實作 .Net MVC Model Validation 自訂驗證規則能有所幫助。

作者: Steven Tsai

大家好, 我是 Steven Tsai, 目前在叡揚資訊技術開發中心(TDS/DC)擔任程式分析師(PA), 在公司主要負責支援其他部門的專案開發, 並樂於協助及解決新人與其他同仁在開發技術上所遇到的瓶頸. 往後也會陸續將學習心得與開發經驗整理並記錄到 Blog 上, 歡迎志同道合的朋友們一起加入討論與研究. Steven's Tech Notepad

發表迴響

你的電子郵件位址並不會被公開。 必要欄位標記為 *