[ASP.NET MVC]自訂屬性自訂資料模型中的資料欄位驗證

之前寫過一篇ASP.NET MVC使用 DataAnnotations 屬性顯示欄位的中文名稱,當然也可以用Required屬性來驗證該欄位在前端網頁是否必填。

但是我想指定其中兩個欄位是至少要一個必填就好了的話,是否也可以透過屬性來驗證呢?

當然可以,不過這得要借助自訂屬性來處理。

假設我有一個資料表:Customer,這個資料表放的資料如(圖一)所示

(圖一)

建完Controller&View,同時也將Csutomer.partial.cs也建立好,我期望是每個欄位都要輸入,所以將Required屬性都加上去。

[MetadataType(typeof(CustomerMD))]
public partial class Customer
{
    public class CustomerMD
    {
        [Required]
        [Display(Name ="姓名")]
        public string name { get; set; }
        
        [Required]
        [Display(Name = "市話")]
        public string phone { get; set; }
        
        [Required]
        [Display(Name = "行動電話")]
        public string mobile { get; set; }
        
        [Required]
        [Display(Name = "地址")]
        public string address { get; set; }
    }
}

所以跑出來的結果就會是像(圖二)這樣

(圖二) 

實際考量後,其實『市話』跟『行動電話』兩者不一定都會有,所以要調整成『市話』跟『行動電話』至少填一個。

但是Required屬性沒辦法達到我想要的需求,所以自己來定義一個屬性

首先,先新增一個class,我自定義名稱為CustomRequired,繼承ValidationAttribute,詳細做法如下

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;

namespace WebApplication1.Models
{
    //因為我屬性要只能套用至Class,所以我在下方要加上這段
    [AttributeUsage(AttributeTargets.Class)]
    public class CustomRequired : ValidationAttribute
    {
        /// <summary> 傳入要綁一起的欄位名稱
        /// </summary>
        public string[] arg { get; private set; }

        /// <summary> 建構子
        /// </summary>
        /// <param name="_arg"></param>
        public CustomRequired(params string[] _arg)
        {
            this.arg = _arg;
        }

        //覆寫IsValid
        public override bool IsValid(object value)
        {
            var result = ValidationResult.Success;
            var typeInfo = value.GetType();
            var propertyInfo = typeInfo.GetProperties();

            //如果有傳入欄位名稱,則驗證這些欄位名稱是否有值,只要有一個有值,就回傳true
            if (this.arg != null)
            {
                foreach (string item in this.arg)
                {
                    if (propertyInfo.Where(p => p.Name == item).FirstOrDefault() != null)
                    {
                        if (propertyInfo.Where(p => p.Name == item).First().GetValue(value, null) != null)
                        {
                            return true;
                        }
                    }
                }
            }
            ///若走到這一步,表示沒有一個欄位有值,這就不符合我們預期的至少一個欄位必填的原則,於是回傳false
            ///其中ErrorMessage可以在設定屬性的時候給予。
            result = new ValidationResult(ErrorMessage);
            return false;
        }
    }
}

設定完後,就可以在Customer.partial.cs上動手腳了,在上方加入剛剛自訂好的屬性,然後將phone與mobile的Required屬性拿掉。

public partial class Customer
{
    [CustomRequired("phone", "mobile", ErrorMessage = "『市話』跟『行動電話』至少填一個")]
    public class CustomerMD
    {
        [Required]
        [Display(Name = "姓名")]
        public string name { get; set; }

        [Display(Name = "市話")]
        public string phone { get; set; }

        [Display(Name = "行動電話")]
        public string mobile { get; set; }

        [Required]
        [Display(Name = "地址")]
        public string address { get; set; }
    }
}

然後去新增畫面輸入姓名與地址,接著直接按下Create,登登~~

(圖三)

如(圖三)所示,出現了紅框部分,而顯示的訊息就如在程式指定的訊息。

 

總結:

這個是不是相當有趣呢,當然不只是Class可以設定,也可以針對欄位做這樣的自定屬性功能,這樣做對我來說好處挺大的,不需要再撰寫一堆JavaScript去判斷。

另外也可以撰寫判斷兩個時間欄位起迄或是限制區間多少...等等,這樣做成共用的模組也是挺方便的。

 

參考資料

 

創用 CC 授權條款
本著作由Chenting Weng製作,以創用CC 姓名標示 4.0 國際 授權條款釋出。
This work by Chenting Weng is licensed under a Creative Commons Attribution 4.0 International License.
Based on a work at https://dotblogs.com.tw/chentingw.

部分文章內容會引用到其他網站的簡介或圖片,若有侵犯到您的著作權,請留言告知,本人會儘快移除。
免責聲明:文章屬個人記事使用,僅供參考,若引用文章造成一切損失,本人不承擔任何責任。如有錯誤,歡迎留言告知。

Part of the content of the article will refer to the profile or picture of other websites.
If there is any infringement of your copyright, please leave a message and let me remove it as soon as possible.
Disclaimer:The article is for personal use and is for reference only. I will not bear any responsibility for any loss caused by quoting the article. If there is an error, please leave a message to inform.