Validus 4.1.4

dotnet add package Validus --version 4.1.4                
NuGet\Install-Package Validus -Version 4.1.4                
此命令旨在在 Visual Studio 的包管理器控制台中使用,因为它使用 NuGet 模块的 Install-Package 版本。
<PackageReference Include="Validus" Version="4.1.4" />                
对于支持 PackageReference 的项目,请将此 XML 节点复制到项目文件中以引用包。
paket add Validus --version 4.1.4                
#r "nuget: Validus, 4.1.4"                
#r 指令可用于 F# Interactive 和 Polyglot Notebooks。请将此内容复制到交互式工具或脚本的源代码以引用包。
// Install Validus as a Cake Addin
#addin nuget:?package=Validus&version=4.1.4

// Install Validus as a Cake Tool
#tool nuget:?package=Validus&version=4.1.4                

Validus

NuGet Version build

Validus 是一个可扩展的 F# 验证库,具有大多数原始类型和内置验证器,可以通过自定义验证器轻松扩展。

主要特性

快速入门

从不受信任的源获取输入的常见示例 PersonDto(例如,HTML 表单提交),应用验证并根据成功/失败产生结果。

open System
open System.Net.Mail
open Validus

type PersonDto =
    { FirstName : string
      LastName  : string
      Email     : string
      Age       : int option
      StartDate : DateTime option }

type Name =
    { First : string
      Last  : string }

type Person =
    { Name      : Name
      Email     : string
      Age       : int option
      StartDate : DateTime }

module Person =
    let ofDto (dto : PersonDto) =
        // A basic validator
        let nameValidator =
            Check.String.betweenLen 3 64

        // A custom email validator, using the *built-in* functionality
        // from System.Net.Mail
        let emailValidator =
            let msg = sprintf "Please provide a valid %s"
            let rule v =
                let success, _ = MailAddress.TryCreate v
                success
            Validator.create msg rule

        // Composing multiple validators to form complex validation rules,
        // overriding default error message (Note: "Check.WithMessage.String" as
        // opposed to "Check.String")
        let emailValidator =
            let emailPatternValidator =
                let msg = sprintf "Please provide a valid %s"
                Check.WithMessage.String.pattern @"[^@]+@[^\.]+\..+" msg

            ValidatorGroup(Check.String.betweenLen 8 512)
                .And(emailPatternValidator)
                .Build()

        // Defining a validator for an option value
        let ageValidator =
            Check.optional (Check.Int.between 1 100)

        // Defining a validator for an option value that is required
        let dateValidator =
            Check.required (Check.DateTime.greaterThan DateTime.Now)

        validate {
          let! first = nameValidator "First name" dto.FirstName
          and! last = nameValidator "Last name" dto.LastName
          and! email = emailValidator "Email address" dto.Email
          and! age = ageValidator "Age" dto.Age
          and! startDate = dateValidator "Start Date" dto.StartDate

          // Construct Person if all validators return Success
          return {
              Name = { First = first; Last = last }
              Email = email
              Age = age
              StartDate = startDate }
        }

注意:此示例仅用于演示,不建议使用正则表达式尝试验证电子邮件。请使用 System.Net.MailAddress

使用验证器

let dto : PersonDto =
    { FirstName = "John"
      LastName  = "Doe"
      Email     = "john.doe@url.com"
      Age       = Some 63
      StartDate = Some (new DateTime(2058, 1, 1)) }

match validatePersonDto dto with
| Ok p -> printfn "%A" p
| Error e ->
    e
    |> ValidationErrors.toList
    |> Seq.iter (printfn "%s")

验证复杂类型

Validus 包含一个 应用计算表达式,在本例中允许在执行验证器时累积验证错误。

open Validus

type PersonDto =
    { FirstName : string
      LastName  : string
      Age       : int option }

type Name =
    { First : string
      Last  : string }

type Person =
    { Name      : Name
      Age       : int option }

module Person =
    let ofDto (dto : PersonDto) =
        let nameValidator = Check.String.betweenLen 3 64

        let firstNameValidator =
            ValidatorGroup(nameValidator)
                .Then(Check.String.notEquals dto.LastName)
                .Build()

        validate {
          let! first = firstNameValidator "First name" dto.FirstName
          and! last = nameValidator "Last name" dto.LastName
          and! age = Check.optional (Check.Int.between 1 120) "Age" dto.Age

          return {
              Name = { First = first; Last = last }
              Age = age }
        }

创建自定义验证器

open System.Net.Mail
open Validus

let fooValidator =
    let fooRule v = v = "foo"
    let fooMessage = sprintf "%s must be a string that matches 'foo'"
    Validator.create fooMessage fooRule

"bar"
|> fooValidator "Test string"

合并验证器

通过结合使用 ValidatorGroup API 将验证器组合在一起,可以创建复杂的验证链和水闸。对于那些喜欢这种语法风格的人来说,一整套操作符也都可以使用。

open System.Net.Mail
open Validus

let emailPatternValidator =
    let msg = sprintf "The %s input is not formatted as expected"
    Check.WithMessage.String.pattern @"[^@]+@[^\.]+\..+" msg

// A custom validator that uses System.Net.Mail to validate email
let mailAddressValidator =
    let msg = sprintf "The %s input is not a valid email address"
    let rule (x : string) =
        let success, _ = MailAddress.TryCreate x
        success
    Validator.create msg rule

let emailValidator =
    ValidatorGroup(Check.String.betweenLen 8 512)
        .And(emailPatternValidator)
        .Then(mailAddressValidator) // only executes when prior two steps are `Ok`
        .Build()

"fake@test"
|> emailValidator "Login email"

我们可以使用任何验证器或验证器的任意组合来验证集合

let emails = [ "fake@test"; "bob@fsharp.org"; "x" ]

let result =
    emails
    |> List.map (emailValidator "Login email")

值对象

一般来说,创建值对象是一个好主意,有时也被称为 值类型约束原语,以表示比通常用于表示它们的原始类型更具体的单个数据点。

示例 1:电子邮件地址值对象

一个很好的例子是将电子邮件地址表示为一个 string 文字,因为它存在于许多程序中。然而,这种方法是有缺陷的,因为电子邮件地址的域比字符串允许的范围更窄。例如,""null 不是有效的电子邮件地址。

为了解决这个问题,我们可以创建一个包装类型来表示电子邮件地址,它隐藏实现细节并提供了生成类型的智能构造。

open System.Net.Mail

type Email =
    private { Email : string }

    override x.ToString () = x.Email

    // Note the transformation from string -> Email
    static member Of : Validator<string, Email> = fun field input ->
        let rule (x : string) =
            if x = "" then false
            else
                try
                    let addr = MailAddress(x)
                    if addr.Address = x then true
                    else false
                with
                | :? FormatException -> false

        let message = sprintf "%s must be a valid email address"

        input
        |> Validator.create message rule field
        |> Result.map (fun v -> { Email = v })

示例 2:E164 格式化电话号码

type E164 =
    private { E164 : string }

    override x.ToString() = x.E164

    static member Of : Validator<string, E164> = fun field input ->
        let e164Regex = @"^\+[1-9]\d{1,14}$"
        let message = sprintf "%s must be a valid E164 telephone number"

        input
        |> Check.WithMessage.String.pattern e164Regex message field
        |> Result.map (fun v -> { E164 = v })

内置验证器

注意:预设了英文语言默认错误消息的验证器位于 Check 模块中。

equals

适用范围:string, int16, int, int64, decimal, float, DateTime, DateTimeOffset, TimeSpan, 'a array, 'a list, 'a seq

open Validus

// Define a validator which checks if a string equals
// "foo" displaying the standard error message.
let equalsFoo =
  Check.String.equals "foo" "fieldName"

equalsFoo "bar"

// Define a validator which checks if a string equals
// "foo" displaying a custom error message (string -> string).
let equalsFooCustom =
  let msg = sprintf "%s must equal the word 'foo'"
  Check.WithMessage.String.equals "foo" msg "fieldName"

equalsFooCustom "bar"

notEquals

适用范围:string, int16, int, int64, decimal, float, DateTime, DateTimeOffset, TimeSpan, 'a array, 'a list, 'a seq

open Validus

// Define a validator which checks if a string is not
// equal to "foo" displaying the standard error message.
let notEqualsFoo =
  Check.String.notEquals "foo" "fieldName"

notEqualsFoo "bar"

// Define a validator which checks if a string is not
// equal to "foo" displaying a custom error message (string -> string)
let notEqualsFooCustom =
  let msg = sprintf "%s must not equal the word 'foo'"
  Check.WithMessage.String.notEquals "foo" msg "fieldName"

notEqualsFooCustom "bar"

between

适用范围:int16, int, int64, decimal, float, DateTime, DateTimeOffset, TimeSpan

open Validus

// Define a validator which checks if an int is between
// 1 and 100 (inclusive) displaying the standard error message.
let between1and100 =
  Check.Int.between 1 100 "fieldName"

between1and100 12 // Result<int, ValidationErrors>

// Define a validator which checks if an int is between
// 1 and 100 (inclusive) displaying a custom error message.
let between1and100Custom =
  let msg = sprintf "%s must be between 1 and 100"
  Check.WithMessage.Int.between 1 100 msg "fieldName"

between1and100Custom 12 // Result<int, ValidationErrors>

greaterThan

适用范围:int16, int, int64, decimal, float, DateTime, DateTimeOffset, TimeSpan

open Validus

// Define a validator which checks if an int is greater than
// 100 displaying the standard error message.
let greaterThan100 =
  Check.Int.greaterThan 100 "fieldName"

greaterThan100 12 // Result<int, ValidationErrors>

// Define a validator which checks if an int is greater than
// 100 displaying a custom error message.
let greaterThan100Custom =
  let msg = sprintf "%s must be greater than 100"
  Check.WithMessage.Int.greaterThan 100 msg "fieldName"

greaterThan100Custom 12 // Result<int, ValidationErrors>

greaterThanOrEqualTo

适用范围:int16, int, int64, decimal, float, DateTime, DateTimeOffset, TimeSpan

open Validus

// Define a validator which checks if an int is greater than
// or equal to 100 displaying the standard error message.
let greaterThanOrEqualTo100 =
  Check.Int.greaterThanOrEqualTo 100 "fieldName"

greaterThanOrEqualTo100 12 // Result<int, ValidationErrors>

// Define a validator which checks if an int is greater than
// or equal to 100 displaying a custom error message.
let greaterThanOrEqualTo100Custom =
  let msg = sprintf "%s must be greater than or equal to 100"
  Check.WithMessage.Int.greaterThanOrEqualTo 100 msg "fieldName"

greaterThanOrEqualTo100Custom 12 // Result<int, ValidationErrors>

lessThan

适用范围:int16, int, int64, decimal, float, DateTime, DateTimeOffset, TimeSpan

open Validus

// Define a validator which checks if an int is less than
// 100 displaying the standard error message.
let lessThan100 =
  Check.Int.lessThan 100 "fieldName"

lessThan100 12 // Result<int, ValidationErrors>

// Define a validator which checks if an int is less than
// 100 displaying a custom error message.
let lessThan100Custom =
  let msg = sprintf "%s must be less than 100"
  Check.WithMessage.Int.lessThan 100 msg "fieldName"

lessThan100Custom 12 // Result<int, ValidationErrors>

lessThanOrEqualTo

适用范围:int16, int, int64, decimal, float, DateTime, DateTimeOffset, TimeSpan

open Validus

// Define a validator which checks if an int is less than
// or equal to 100 displaying the standard error message.
let lessThanOrEqualTo100 =
  Check.Int.lessThanOrEqualTo 100 "fieldName"

lessThanOrEqualTo100 12 // Result<int, ValidationErrors>

// Define a validator which checks if an int is less than
// or equal to 100 displaying a custom error message.
let lessThanOrEqualTo100Custom =
  let msg = sprintf "%s must be less than or equal to 100"
  Check.WithMessage.Int.lessThanOrEqualTo 100 msg "fieldName"

lessThanOrEqualTo100Custom 12 // Result<int, ValidationErrors>

betweenLen

适用范围:string, 'a array, 'a list, 'a seq

open Validus

// Define a validator which checks if a string is between
// 1 and 100 chars displaying the standard error message.
let between1and100Chars =
  Check.String.betweenLen 1 100 "fieldName"

between1and100Chars "validus"

// Define a validator which checks if a string is between
// 1 and 100 chars displaying a custom error message.
let between1and100CharsCustom =
  let msg = sprintf "%s must be between 1 and 100 chars"
  Check.WithMessage.String.betweenLen 1 100 msg "fieldName"

between1and100CharsCustom "validus"

equalsLen

适用范围:string, 'a array, 'a list, 'a seq

open Validus

// Define a validator which checks if a string is equals to
// 100 chars displaying the standard error message.
let equals100Chars =
  Check.String.equalsLen 100 "fieldName"

equals100Chars "validus"

// Define a validator which checks if a string is equals to
// 100 chars displaying a custom error message.
let equals100CharsCustom =
  let msg = sprintf "%s must be 100 chars"
  Check.WithMessage.String.equalsLen 100 msg "fieldName"

equals100CharsCustom "validus"

greaterThanLen

适用范围:string, 'a array, 'a list, 'a seq

open Validus

// Define a validator which checks if a string is greater than
// 100 chars displaying the standard error message.
let greaterThan100Chars =
  Check.String.greaterThanLen 100 "fieldName"

greaterThan100Chars "validus"

// Define a validator which checks if a string is greater than
// 100 chars displaying a custom error message.
let greaterThan100CharsCustom =
  let msg = sprintf "%s must be greater than 100 chars"
  Check.WithMessage.String.greaterThanLen 100 msg "fieldName"

greaterThan100CharsCustom "validus"

greaterThanOrEqualToLen

适用范围:string, 'a array, 'a list, 'a seq

open Validus

// Define a validator which checks if a string is greater than
// or equal to 100 chars displaying the standard error message.
let greaterThanOrEqualTo100Chars =
  Check.String.greaterThanOrEqualToLen 100 "fieldName"

greaterThanOrEqualTo100Chars "validus"

// Define a validator which checks if a string is greater than
// or equal to 100 chars displaying a custom error message.
let greaterThanOrEqualTo100CharsCustom =
  let msg = sprintf "%s must be greater than or equal to 100 chars"
  Check.WithMessage.String.greaterThanOrEqualToLen 100 msg "fieldName"

greaterThanOrEqualTo100CharsCustom "validus"

lessThanLen

适用范围:string, 'a array, 'a list, 'a seq

open Validus

// Define a validator which checks if a string is less tha
// 100 chars displaying the standard error message.
let lessThan100Chars =
  Check.String.lessThanLen 100 "fieldName"

lessThan100Chars "validus"

// Define a validator which checks if a string is less tha
// 100 chars displaying a custom error message.
let lessThan100CharsCustom =
  let msg = sprintf "%s must be less than 100 chars"
  Check.WithMessage.String.lessThanLen 100 msg "fieldName"

lessThan100CharsCustom "validus"

lessThanOrEqualToLen

适用范围:string, 'a array, 'a list, 'a seq

open Validus

// Define a validator which checks if a string is less tha
// or equal to 100 chars displaying the standard error message.
let lessThanOrEqualTo100Chars =
  Check.String.lessThanOrEqualToLen 100 "fieldName"

lessThanOrEqualTo100Chars "validus"

// Define a validator which checks if a string is less tha
// or equal to 100 chars displaying a custom error message.
let lessThanOrEqualTo100CharsCustom =
  let msg = sprintf "%s must be less than 100 chars"
  Check.WithMessage.String.lessThanOrEqualToLen 100 msg "fieldName"

lessThanOrEqualTo100CharsCustom "validus"

empty

适用范围:string, 'a array, 'a list, 'a seq

open Validus

// Define a validator which checks if a string is empty
// displaying the standard error message.
let stringIsEmpty =
  Check.String.empty "fieldName"

stringIsEmpty "validus"

// Define a validator which checks if a string is empty
// displaying a custom error message.
let stringIsEmptyCustom =
  let msg = sprintf "%s must be empty"
  Check.WithMessage.String.empty msg "fieldName"

stringIsEmptyCustom "validus"

notEmpty

适用范围:string, 'a array, 'a list, 'a seq

open Validus

// Define a validator which checks if a string is not empty
// displaying the standard error message.
let stringIsNotEmpty =
  Check.String.notEmpty "fieldName"

stringIsNotEmpty "validus"

// Define a validator which checks if a string is not empty
// displaying a custom error message.
let stringIsNotEmptyCustom =
  let msg = sprintf "%s must not be empty"
  Check.WithMessage.String.notEmpty msg "fieldName"

stringIsNotEmptyCustom "validus"

pattern

适用范围:string

open Validus

// Define a validator which checks if a string matches the
// provided regex displaying the standard error message.
let stringIsChars =
  Check.String.pattern "[a-z]+" "fieldName"

stringIsChars "validus"

// Define a validator which checks if a string matches the
// provided regex displaying a custom error message.
let stringIsCharsCustom =
  let msg = sprintf "%s must follow the pattern [a-z]"
  Check.WithMessage.String.pattern "[a-z]" msg "fieldName"

stringIsCharsCustom "validus"

exists

适用范围:'a array, 'a list, 'a seq

open Validus

// Define a validator which checks if a collection matches the provided predicate
// displaying the standard error message.
let collectionContains =
  Check.List.exists (fun x -> x = 1) "fieldName"

collectionContains [1]

// Define a validator which checks if a string is not empty
// displaying a custom error message.
let collectionContainsCustom =
  let msg = sprintf "%s must contain the value '1'"
  Check.WithMessage.List.exists (fun x -> x = 1) msg "fieldName"

collectionContainsCustom [1]

自定义操作符

操作符 描述
<+> 组合两个相同类型的验证器
*\|* 将验证器的 Ok 结果映射到,用于选择 <\|> 的高优先级。
*\| 将验证器的 Ok 结果设置为固定值,用于选择 <\|> 的高优先级。
>>\| 将验证器的 Ok 结果映射到,用于链式验证的低优先级
>\| 将验证器的 Ok 结果设置为固定值,用于链式验证的低优先级
>>= 将验证器的 Ok 结果与返回 Result 的单参数函数绑定
<<= 将验证器的 Ok 结果与返回 Result 的单参数函数反绑定
>>% 将验证器的 Ok 结果设置为固定的 Result 值
<\|> 引入选择:如果右侧验证 Ok,则选择该结果,否则继续下一个验证器
>=> 组合两个验证器。除了组合 <+> 外,这可以改变结果类型。
<=< 反向组合两个验证器(右侧先评估)。除了组合 <+> 外,这可以改变结果类型。
.>> 组合两个验证器,但保留左侧的结果。忽略右侧的结果,除非它返回一个错误。
>>. 组合两个验证器,但保留右侧的结果。忽略左侧的结果,除非它返回一个错误。
.>>. 组合两个验证器,并保留两边的嵌套结果作为元组。

使用组合操作符重写上面的示例代码

open System.Net.Mail
open Validus
open Validus.Operators

let msg = sprintf "Please provide a valid %s"

let emailPatternValidator =
    Check.WithMessage.String.pattern @"[^@]+@[^\.]+\..+" msg

// A custom validator that uses System.Net.Mail to validate email
let mailAddressValidator =
    let rule (x : string) =
        if x = "" then false
        else
            try
                let addr = MailAddress(x)
                if addr.Address = x then true
                else false
            with
            | :? FormatException -> false

    Validator.create msg rule

let emailValidator =
    Check.String.betweenLen 8 512 // check string is between 8 and 512 chars
    <+> emailPatternValidator     // and, check string match email regex
    >=> mailAddressValidator      // then, check using System.Net.Mail if prior two steps are `Ok`

"fake@test"
|> emailValidator "Login email"

一个更复杂的例子,涉及到“链式”验证器和两者都涉及“选择”赋值和映射

open System
open Validus
open Validus.Operators

type AgeGroup =
    | Adult of int
    | Child
    | Senior

let ageValidator =
    Check.String.pattern @"\d+" *|* Int32.Parse // if pattern matches, convert to Int32
    >=> Check.Int.between 0 120                 // first check age between 0 and 120
    >=> (Check.Int.between 0 17  *| Child       // then, check age between 0 an 17 assigning Child
    <|> Check.Int.greaterThan 65 *| Senior      // or, check age greater than 65 assiging Senior
    <|> Check.Int.between 18 65  *|* Adult)     // or, check age between 18 and 65 assigning adult mapping converted input

发现错误了吗?

有一个问题与此相关。

许可证

由Pim Brouwers在多伦多创建,并使用♥。许可证遵循Pim BrouwersApache License 2.0

产品 兼容的以及额外的计算目标框架版本。
.NET net5.0 已计算。 net5.0-windows 已计算。 net6.0 已计算。 net6.0-android 已计算。 net6.0-ios 已计算。 net6.0-maccatalyst 已计算。 net6.0-macos 已计算。 net6.0-tvos 已计算。 net6.0-windows 已计算。 net7.0 已计算。 net7.0-android 已计算。 net7.0-ios 已计算。 net7.0-maccatalyst 已计算。 net7.0-macos 已计算。 net7.0-tvos 已计算。 net7.0-windows 已计算。 net8.0 已计算。 net8.0-android 已计算。 net8.0-browser 已计算。 net8.0-ios 已计算。 net8.0-maccatalyst 已计算。 net8.0-macos 已计算。 net8.0-tvos 已计算。 net8.0-windows 已计算。
.NET Core netcoreapp2.0 已计算。 netcoreapp2.1 已计算。 netcoreapp2.2 已计算。 netcoreapp3.0 已计算。 netcoreapp3.1 已计算。
.NET Standard netstandard2.0 兼容。 netstandard2.1 已计算。
.NET Framework net461 已计算。 net462 已计算。 net463 已计算。 net47 已计算。 net471 已计算。 net472 已计算。 net48 已计算。 net481 已计算。
MonoAndroid monoandroid 已计算。
MonoMac monomac 已计算。
MonoTouch monotouch 已计算。
Tizen tizen40 已计算。 tizen60 已计算。
Xamarin.iOS xamarinios 已计算。
Xamarin.Mac xamarinmac 已计算。
Xamarin.TVOS xamarintvos 已计算。
Xamarin.WatchOS xamarinwatchos 已计算。
兼容目标框架
包含的目标框架(在包中)
了解更多关于 目标框架.NET Standard 的信息。

NuGet 包

此包不被任何 NuGet 包使用。

GitHub 仓库

此包不被任何流行的 GitHub 仓库使用。

版本 下载 最后更新
4.1.4 1,168 3/15/2024
4.1.3 5,214 7/15/2023
4.1.2 8,335 1/12/2023
4.1.1 260 1/12/2023
4.1.0 502 12/26/2022
4.0.3 298 12/21/2022
4.0.2 717 11/22/2022
4.0.1 1,974 9/19/2022
4.0.0 528 9/5/2022
3.1.0 374 9/1/2022
3.0.1 2,266 12/9/2021
3.0.0 317 9/1/2021
2.0.3 371 8/17/2021
2.0.2 310 8/13/2021
2.0.1 312 8/6/2021
2.0.0 352 7/6/2021
1.4.2 301 6/28/2021
1.4.1 363 6/23/2021
1.3.1 339 6/15/2021
1.3.0 294 6/4/2021
1.2.0 289 6/2/2021
1.1.0 317 6/2/2021
1.0.1 349 4/22/2021
1.0.0 475 11/28/2020
1.0.0-alpha5 248 11/23/2020
1.0.0-alpha4 260 11/23/2020
1.0.0-alpha3 254 11/23/2020
1.0.0-alpha2 224 11/21/2020
1.0.0-alpha1 263 11/20/2020