1. 程式人生 > >WebApi資料驗證——編寫自定義資料註解(Data Annotations)

WebApi資料驗證——編寫自定義資料註解(Data Annotations)

配合ModelState使用,關於使用方法,參考微軟文件

https://docs.microsoft.com/en-us/aspnet/web-api/overview/formats-and-model-binding/model-validation-in-aspnet-web-api

自定義Data Annotations只需要繼承ValidationAttribute,並且重寫IsValid方法。

示例:


// =================================================================== 
// ModelState自定義註解
// 多個欄位分組判斷,全部不允許為空或至少有一個不為空
//====================================================================
// CreateTime:2019-04-24 
// Author:liucx
// ===================================================================
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace OF.Component.Model
{
    /// <summary>
    ///  多個屬性欄位分組不為空判斷  傳入引數逗號間隔
    ///  <example>[GroupEmpty("p1,p2,p3",false,ErrorMessage="p1p2p3三個引數中至少有一個非空")] </example>
    /// </summary>
    public class GroupEmptyAttribute : ValidationAttribute
    {
        private readonly string _groupFields;
        private readonly bool _notNullableAll;
        /// <summary>
        ///  建構函式
        /// </summary>
        /// <param name="groupFields">屬性名,多個屬性名逗號隔開</param>
        /// <param name="notNullableAll"> true全部不允許為空。 false只要存在不為空的屬性即可</param>
        public GroupEmptyAttribute(string groupFields, bool notNullableAll)
        {
            _groupFields = groupFields;
            _notNullableAll = notNullableAll;
        }
        /// <summary>
        /// 建構函式,預設至少1個非空
        /// </summary>
        /// <param name="groupFields">屬性名,多個屬性名逗號隔開</param>
        public GroupEmptyAttribute(string groupFields)
        {
            _groupFields = groupFields;
            _notNullableAll = false;
        }
        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
            var validateResult = false;
            var obj = validationContext.ObjectInstance;
            Type Ts = obj.GetType();
            var fields = _groupFields.Split(',');
            if (fields.Count() > 0)
            {
                for (var i = 0; i < fields.Count(); i++)
                {
                    var filedName = Convert.ToString(fields[i]);
                    if (string.IsNullOrEmpty(filedName)) continue;
                    //value
                    string filedValue = Convert.ToString(Ts.GetProperty(filedName).GetValue(obj, null));
                    //_notNullableAll=true,任意一個為空直接驗證掛掉跳出迴圈
                    if (_notNullableAll && string.IsNullOrWhiteSpace(filedValue))
                    {
                        validateResult = false;
                        break;
                    }
                    //_notNullableAll=false,只要有一個不為空就可以過驗證
                    if (!_notNullableAll && !string.IsNullOrWhiteSpace(filedValue))
                    {
                        validateResult = true;
                        break;
                    }
                }
            }
            //success
            if (validateResult)
                return ValidationResult.Success;
            else
            {
                //fail
                if (string.IsNullOrEmpty(ErrorMessage) && _notNullableAll)
                    return new ValidationResult($"{_groupFields}欄位全部不允許為空值");
                else if (string.IsNullOrEmpty(ErrorMessage) && !_notNullableAll)
                    return new ValidationResult($"{_groupFields}欄位中至少要有一個不為空的值");
                else
                    return new ValidationResult(ErrorMessage);
            }

        }
    }

    /// <summary>
    /// 組內資料同步判斷,同時為空或同時不為空通過驗證
    /// </summary>
    public class GroupEmptySyncAttribute : ValidationAttribute
    {
        private readonly string _groupFields;

        public GroupEmptySyncAttribute(string groupFields)
        {
            _groupFields = groupFields;
        }
        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
            var validateResult = true;
            var obj = validationContext.ObjectInstance;
            Type Ts = obj.GetType();
            var fields = _groupFields.Split(',');
            if (fields.Count() > 0)
            {
                bool firstValueIsEmpty = true;//第一個值是否為空
                for (var i = 0; i < fields.Count(); i++)
                {
                    var filedName = Convert.ToString(fields[i]);
                    if (string.IsNullOrEmpty(filedName)) continue;
                    //value
                    string filedValue = Convert.ToString(Ts.GetProperty(filedName).GetValue(obj, null));
                    //第一個值記錄是否為空
                    if (i == 0 && string.IsNullOrWhiteSpace(filedValue))
                        firstValueIsEmpty = true;
                    if (i == 0 && !string.IsNullOrWhiteSpace(filedValue))
                        firstValueIsEmpty = false;

                    //後續值判斷是否和第一個值符合,不符合直接結束驗證
                    if (i > 0)
                    {
                        if (string.IsNullOrWhiteSpace(filedValue) != firstValueIsEmpty)
                        {
                            validateResult = false;
                            break;
                        }
                    }
                }
            }
            //success
            if (validateResult)
                return ValidationResult.Success;
            else
            {
                //fail
                if (string.IsNullOrEmpty(ErrorMessage))
                    return new ValidationResult($"{_groupFields}欄位是否為空不一致(必須同時為空或同時不為空)");
                else
                    return new ValidationResult(ErrorMessage);
            }

        }
    }

    /// <summary>
    /// 判斷時間格式是否對應,時間格式一致通過驗證
    /// </summary>
    public class DateFormatValidAttribute : ValidationAttribute
    {
        private readonly string _formatStr;
        public DateFormatValidAttribute(string formatStr)
        {
            _formatStr = formatStr;
        }
        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
            var validateResult = false;
            try
            {
                //轉成要求的格式後 再和傳入的值對比
                var formatValue = Convert.ToDateTime((string)value).ToString(_formatStr);
                if ((string)value == formatValue)
                    validateResult = true;
                else
                    validateResult = false;

                //success
                if (validateResult)
                    return ValidationResult.Success;
                else
                {
                    //fail
                    if (string.IsNullOrEmpty(ErrorMessage))
                        return new ValidationResult($"時間格式不符合{_formatStr}格式");
                    else
                        return new ValidationResult(ErrorMessage);
                }
            }
            catch (Exception ex)
            {
                if (string.IsNullOrEmpty(ErrorMessage))
                    return new ValidationResult($"時間格式不符合{_formatStr}格式");
                else
                    return new ValidationResult(ErrorMessage);
            }
        }

    }
}

使用:

測試結果:

相關推薦

WebApi資料驗證——編寫定義資料註解Data Annotations

配合ModelState使用,關於使用方法,參考微軟文件 https://docs.microsoft.com/en-us/as

一句python,一句R︱列表、元組、字典、資料型別、定義模組匯入格式、去重

先學了R,最近剛剛上手python,所以想著將python和R結合起來互相對比來更好理解python。最好就是一句python,對應寫一句R。pandas中有類似R中的read.table的功能,而且很像。———————————————————————————————————

定義Java註解annotation

https://www.imooc.com/learn/456  筆記 Java從1.5開始引進註解。 首先解決一個問題,為什麼要學習Java註解? 1.看懂別人寫的程式碼,尤其是框架的程式碼 2.可以是自己寫的程式碼簡潔清晰   現在開始學習Java註解了。  

ros編寫定義的服務.srv

1、編寫自定義的服務檔案(即.srv)檔案。 2、儲存,catkin_make編譯,要生成可以被#include "包/AddTwoInts.h",注意CMakeList.txt檔案的配置 cmake_minimum_required(VERSION 2.8.3) project(le

Jasper Report之定義組件Custom Visualization環境配置

win 進行 studio one component add 。。 版本 inf Jasper Report提供的功能已經足夠強大了,但是仍不能完全對接客戶的需求,因此需要我們自定義組件完成對我們Report的設計,開發前的環境配置還是個麻煩事。。。 系統:Linux I

vue中定義組件插件

comment tty index all target mark cal ali lan vue中自定義組件(插件) 原創 2017年01月04日 22:46:43 標簽: 插件 在vue項目中,可以自定義組件像vue-resource一樣使用Vue.use(

Xamarin定義佈局系列——ListView的一個定義實現ItemsControl橫向列表

原文: Xamarin自定義佈局系列——ListView的一個自定義實現ItemsControl(橫向列表) 在以前寫UWP程式的時候,瞭解到在ListView或者ListBox這類的列表空間中,有一個叫做ItemsPannel的屬性,它是所有列表中子元素實際的容器,如果要讓列表進行橫向排列,只需要在Xam

VSCode 如何操作使用者定義程式碼片段快捷鍵

如何操作使用者自定義程式碼片段(快捷鍵)? 第一步:檔案==>首選項==>使用者程式碼片段 第二步:選擇程式碼片段檔案 html.json   第三步:輸入要自定義的快捷鍵 和 模板程式碼段 { "vh": { "prefix

Django 框架中的定義模板標籤template.Library()

某一些標籤(例如:選單欄、css、JS、以及一些複雜計算後的資料等)需要我們自定義。 然後再在指定的html中引用並顯示。 之所以要用到標籤,主要作用就是想讓一些內容在多個模板(HTML)中都要有,比如選單欄。 我們絕對不想在每個檢視函式(views中)都寫一次這些變數內容。 即每個頁面

SpringBoot定義配置檔案xxx.properties

轉載 :https://www.cnblogs.com/V1haoge/p/7183408.htmlSpringBoot中免除了大部分手動配置,但是對於一些特定的情況,還是需要我們進行手動配置的,SpringBoot為我們提供了application.properties配置檔案,讓我們可以進行自定義配置,來

Rabbit MQ 定義監聽器容器Listener Container的啟動與停止

專案中會遇到,MQ佇列的監聽是在某一前提條件準備好的情況下才啟動,比如MQ接收到一系列資料,這些資料的儲存依賴於另外一個MQ訊息的一些配置接收之後才能完成。 指定屬性autoStartup為false,並啟動對應的listener id @RabbitHandl

spring-security 個性化使用者認證流程——定義登入頁面可配置

1.定義自己的登入頁面我們需要根據自己的業務系統構建自己的登入頁面以及登入成功、失敗處理在spring security提供給我的登入頁面中,只有使用者名稱、密碼框,而自帶的登入成功頁面是空白頁面(可以重定向之前請求的路徑中),而登入失敗時也只是提示使用者被鎖定、過期等資訊。 在實際的開發中,則需要更

微信小程式之——定義分享按鈕完整版

1.宣告 onShareAppMessage 函式   onShareAppMessage() {          return {        title: '彈出分享時顯示的分享標

定義標籤庫Tag library

簡介 JSP標籤庫技術可以讓我們定製自己的標籤。 我們前邊講解了JSP動作標籤,動作標籤本質上就是一段Java程式碼,在JSP頁面被轉換為Servlet期間,JSP引擎解析到JSP檔案就會將動作標籤轉換為我們預先定義好的Java程式碼。 同樣,自定義標籤實際上一個實現了特定介面

配置RedisTemplate、JedisPoolConfig、JedisConnectionFactory+定義序列化 java方式

java方式配置RedisTemplate   //spring注入ben    //@Bean(name = "redisTemplate") public RedisTemplate initRedisTemplate(){ JedisPoolConfig poolCo

定義字典樹字首樹

通過學習自定義字典樹,瞭解字典樹這一資料結構。   之前的二分搜尋樹(二叉樹)、堆(完全二叉樹)、線段樹(平衡二叉樹)都是基於二叉樹。而字典樹是一種多叉樹。     如果有n個條目,使用樹結構查詢的時間複雜度為O(log n),如果有100

定義線段樹區間樹

通過學習自定義線段樹(區間樹),瞭解線段樹這一資料結構。 線段樹首先是平衡二叉樹。   用例:查詢一個區間[i,j]的最大值,最小值,或者區間數字和等。 實質:基於區間的統計查詢。 為什麼用線段樹:   使用陣列

Qt之定義控制元件開關按鈕

簡述 接觸過iOS系統的童鞋們應該對開關按鈕很熟悉,在設定裡面經常遇到,切換時候的滑動效果比較帥氣。 通常說的開關按鈕,有兩個狀態:on、off。 下面,我們利用自定義控制元件來實現一個開關按鈕。 原理 重寫滑鼠按下事件(mousePres

Android定義View-TitleBar標題欄詳細說明

我們在開發Android介面時常常要在許多頁面中共用風格相似的標題欄,為了減少重複性工作我們可以將標題欄做成一個通用的自定義控制元件。 我將通過兩種形式的自定義方式介紹自定義TitleBar 第一種方式(不涉及自定義屬性) 首先通過在Layout中建一個佈局檔案先確定Ti

C# WinForm中如何定義config檔案XML檔案,並且讀取和儲存它

我這裡以連結資料庫為例子, 其中書寫的Config的xml檔案如下: <?xml version="1.0" encoding="utf-8"?> <configuration>   <appSettings>     <add k