参照 FluentValidation 的官方文档写的例子,方便日后查看和使用。

原文:https://github.com/JeremySkinner/FluentValidation/wiki

Home

NuGet Packages

Install-Package FluentValidation

For ASP.NET MVC integration:

Install-Package FluentValidation.MVC5

For ASP.NET Core:

Install-Package FluentValidation.AspNetCore

Example

using FluentValidation;

public class CustomerValidator: AbstractValidator<Customer> {
public CustomerValidator() {
RuleFor(customer => customer.Surname).NotEmpty();
RuleFor(customer => customer.Forename).NotEmpty().WithMessage("Please specify a first name");
RuleFor(customer => customer.Discount).NotEqual(0).When(customer => customer.HasDiscount);
RuleFor(customer => customer.Address).Length(20, 250);
RuleFor(customer => customer.Postcode).Must(BeAValidPostcode).WithMessage("Please specify a valid postcode");
} private bool BeAValidPostcode(string postcode) {
// custom postcode validating logic goes here
}
} Customer customer = new Customer();
CustomerValidator validator = new CustomerValidator();
ValidationResult results = validator.Validate(customer); bool validationSucceeded = results.IsValid;
IList<ValidationFailure> failures = results.Errors;

a.Index

Documentation table of contents

b. Creating a Validator

定义对象,及对象验证类

    public class Customer
{
public int Id { get; set; }
public string Surname { get; set; }
public string Forename { get; set; }
public decimal Discount { get; set; }
public Address Address { get; set; }
public List<string> AddressLines { get; set; } = new List<string>();
public IList<Order> Orders { get; set; }
} /// <summary>
/// 为Customer类定义一组规则,继承自AbstractValidator<Customer>
/// </summary>
public class CustomerValidator : AbstractValidator<Customer>
{
public CustomerValidator()
{
//多个验证规则
RuleFor(customer => customer.Surname).NotNull().NotEqual("foo"); //对集合中的每一项进行验证
RuleForEach(x => x.AddressLines).NotNull(); //复合属性验证的重新利用
RuleFor(customer => customer.Address).SetValidator(new AddressValidator()); //复合的集合属性验证的重新利用
RuleFor(x => x.Orders).SetCollectionValidator(new OrderValidator());
//用Where方法选择性验证某些项
RuleFor(x => x.Orders).SetCollectionValidator(new OrderValidator()).Where(x => x.Cost != null); //定义名为“Names”的规则集合
RuleSet("Names", () =>
{
RuleFor(x => x.Surname).NotNull();
RuleFor(x => x.Forename).NotNull();
});
}
}
    public class Address
{
public string Line1 { get; set; }
public string Line2 { get; set; }
public string Town { get; set; }
public string County { get; set; }
public string Postcode { get; set; }
}
public class AddressValidator : AbstractValidator<Address>
{
public AddressValidator()
{
RuleFor(address => address.Postcode).NotNull();
//etc
}
}
    public class Order
{
public string ProductName { get; set; }
public decimal? Cost { get; set; }
}
public class OrderValidator : AbstractValidator<Order>
{
public OrderValidator()
{
RuleFor(x => x.ProductName).NotNull();
RuleFor(x => x.Cost).GreaterThan(0);
}
}

调用

        public void Validate()
{
Customer customer = new Customer();
customer.Orders = new List<Order> {
new Order { ProductName = "Foo" },
new Order { Cost = 5 }
}; CustomerValidator validator = new CustomerValidator();
ValidationResult results = validator.Validate(customer); //将复杂的验证定义分解到较小的片段中,可独立使用
//把多个规则聚集都一个规则集合中
var result1 = validator.Validate(customer, ruleSet: "Names");
//多个规则集合
var result2 = validator.Validate(customer, ruleSet: "Names,MyRuleSet,SomeOtherRuleSet");
//不在任何规则集合中的default
var result3 = validator.Validate(customer, ruleSet: "default,MyRuleSet"); if (!results.IsValid)
{
foreach (var failure in results.Errors)
{
Console.WriteLine("Property " + failure.PropertyName + " failed validation. Error was: " + failure.ErrorMessage);
}
} //抛出异常
validator.ValidateAndThrow(customer); }

c. Built In Validators 内置验证器

//Ensures that the specified property is not null.
RuleFor(customer => customer.Surname).NotNull(); //Ensures that the specified property is not null, an empty string or whitespace (or the default value for value types, eg 0 for int)
RuleFor(customer => customer.Surname).NotEmpty(); //Not equal to a particular value
RuleFor(customer => customer.Surname).NotEqual("Foo");
//Not equal to another property
RuleFor(customer => customer.Surname).NotEqual(customer => customer.Forename); //Equal to a particular value
RuleFor(customer => customer.Surname).Equal("Foo");
//Equal to another property
RuleFor(customer => customer.Password).Equal(customer => customer.PasswordConfirmation); //must be between 1 and 250 chars (inclusive)
RuleFor(customer => customer.Surname).Length(1, 250); //Less than a particular value
RuleFor(customer => customer.CreditLimit).LessThan(100);
//Less than another property
RuleFor(customer => customer.CreditLimit).LessThan(customer => customer.MaxCreditLimit); //Less than a particular value
RuleFor(customer => customer.CreditLimit).LessThanOrEqualTo(100);
//Less than another property
RuleFor(customer => customer.CreditLimit).LessThanOrEqualTo(customer => customer.MaxCreditLimit); //Greater than a particular value
RuleFor(customer => customer.CreditLimit).GreaterThan(0);
//Greater than another property
RuleFor(customer => customer.CreditLimit).GreaterThan(customer => customer.MinimumCreditLimit); //Greater than a particular value
RuleFor(customer => customer.CreditLimit).GreaterThanOrEqualTo(1);
//Greater than another property
RuleFor(customer => customer.CreditLimit).GreaterThanOrEqualTo(customer => customer.MinimumCreditLimit); //Passes the value of the specified property into a delegate that can perform custom validation logic on the value
//Also known as "Must"
RuleFor(customer => customer.Surname).Must(surname => surname == "Foo");
//Note that there is an additional overload for Must that also accepts an instance of the parent object being validated.
//This can be useful if you want to compare the current property with another property from inside the predicate:
//Note that in this particular example, it would be better to use the cross-property version of NotEqual
RuleFor(customer => customer.Surname).Must((customer, surname) => surname != customer.Forename); //Ensures that the value of the specified property matches the given regular expression. Example:
RuleFor(customer => customer.Surname).Matches("some regex here"); //Ensures that the value of the specified property is a valid email address format. Example:
RuleFor(customer => customer.Email).EmailAddress();

d. Configuring a Validator 配置验证器

1.Override the default error message

RuleFor(customer => customer.Surname).NotNull().WithMessage("Please ensure that you have entered your Surname");
//'{PropertyName}' will be replaced with the name of the property being validated
//and the value 'Surname' will be inserted.
RuleFor(customer => customer.Surname).NotNull().WithMessage("Please ensure you have entered your {PropertyName}");
Configuring Error Message Parameters (Placeholders)

The placeholders are Used in all validators:
'{PropertyName}' - The name of the property being validated
'{PropertyValue}' - The value of the property being validated These include the predicate validator('Must' validator), the email and the regex validators. Used in comparison validators: (Equal, NotEqual, GreaterThan, GreaterThanOrEqual, etc.)
{ ComparisonValue} = Value that the property should be compared to Used only in the Length validator:
{ MinLength} = Minimum length
{ MaxLength} = Maximum length
{ TotalLength} = Number of characters entered
//Using static values in a custom message:
RuleFor(customer => customer.Surname).NotNull()
.WithMessage(customer => string.Format("This message references some constant values: {0} {1}", "hello", 5));
//Result would be "This message references some constant values: hello 5" //Referencing other property values:
RuleFor(customer => customer.Surname).NotNull()
.WithMessage(customer => $"This message references some other properties: Forename: {customer.Forename} Discount: {customer.Discount}");
//Result would be: "This message references some other properties: Forename: Jeremy Discount: 100"

2.Overriding the Default Property Name

//The default error message would be 'Surname' must not be empty.
RuleFor(customer => customer.Surname).NotNull();
//Replace just the property name by calling WithName
//Now the error message would be 'Last name' must not be empty.
RuleFor(customer => customer.Surname).NotNull().WithName("Last name");
//Completely rename the property, including the Errors collection on the ValidationResult
RuleFor(customer => customer.Surname).NotNull().OverridePropertyName("Last name");
//Property name resolution is also pluggable.By default, the name of the property extracted from the MemberExpression passed to RuleFor. If you want change this logic, you can set the DisplayNameResolver property on the ValidatorOptions class.
//这段不是太懂
ValidatorOptions.DisplayNameResolver = (type, member) => {
if (member != null)
{
return member.Name + "Foo";
}
return null;
};
//另外,FluentValidation 可采用 DisplayName and Display attributes,来生成错误信息中的属性名,同 WithName
public class Person
{
[Display(Name = "Last name")]
public string Surname { get; set; }
}

3.Specifying a condition with When/Unless 指定条件

//当满足条件时才执行验证规则(Unless则相反)
RuleFor(customer => customer.CustomerDiscount).GreaterThan(0).When(customer => customer.IsPreferredCustomer); //同时应用到多条规则
When(customer => customer.IsPreferred, () =>
{
RuleFor(customer => customer.CustomerDiscount).GreaterThan(0);
RuleFor(customer => customer.CreditCardNumber).NotNull();
});

4.Setting the Cascade mode 设置级联模式

//默认是第一个验证失败后,继续执行第二个验证
RuleFor(x => x.Surname).NotNull().NotEqual("foo");
//第一个验证失败后停止,不再验证之后的规则
RuleFor(x => x.Surname).Cascade(CascadeMode.StopOnFirstFailure).NotNull().NotEqual("foo");
The two cascade modes are:
Continue(the default) - always invokes all validators in a rule definition
StopOnFirstFailure - stops executing a rule as soon as a validator fails
//在应用程序启动入口设置全局级联模式
//这会被具体的验证器类和具体的验证规则重写
ValidatorOptions.CascadeMode = CascadeMode.StopOnFirstFailure;
//在单个验证器类中设置级联模式
public class PersonValidator : AbstractValidator<Person>
{
public PersonValidator()
{
// First set the cascade mode
CascadeMode = CascadeMode.StopOnFirstFailure; //Rule definitions follow
//RuleFor(...)
//RuleFor(...)
}
}

e. Custom Validators 定制验证器

1.Using the Predicate Validator 使用断言验证器

public class Person
{
public IList<Pet> Pets { get; set; } = new List<Pet>();
}
public class PersonValidator : AbstractValidator<Person>
{
public PersonValidator()
{
RuleFor(x => x.Pets).Must(list => list.Count <= 10).WithMessage("The list must contain fewer than 10 items");
}
}
//封装成扩展方法,使其可重用
public static class MyCustomValidators
{
public static IRuleBuilderOptions<T, IList<TElement>> ListMustContainFewerThan<T, TElement>(this IRuleBuilder<T, IList<TElement>> ruleBuilder, int num)
{
return ruleBuilder.Must(list => list.Count < num).WithMessage("The list contains too many items");
}
}
RuleFor(x => x.Pets).ListMustContainFewerThan(10);

Using a custom message placeholder 定制消息

//The resulting message will now be 'Pets' must contain fewer than 10 items.
public static IRuleBuilderOptions<T, IList<TElement>> ListMustContainFewerThan<T, TElement>(this IRuleBuilder<T, IList<TElement>> ruleBuilder, int num)
{
return ruleBuilder.Must((rootObject, list, context) =>
{
context.MessageFormatter.AppendArgument("MaxElements", num);
return list.Count < num;
})
.WithMessage("{PropertyName} must contain fewer than {MaxElements} items.");
} public static IRuleBuilderOptions<T, IList<TElement>> ListMustContainFewerThan<T, TElement>(this IRuleBuilder<T, IList<TElement>> ruleBuilder, int num)
{
return ruleBuilder.Must((rootObject, list, context) =>
{
context.MessageFormatter
.AppendArgument("MaxElements", num)
.AppendArgument("TotalElements", list.Count); return list.Count < num;
})
.WithMessage("{PropertyName} must contain fewer than {MaxElements} items. The list contains {TotalElements} element");
}

2.Using a Custom Validator 使用定制验证器

//This method allows you to manually create the ValidationFailure instance associated with the validation error.
RuleFor(x => x.Pets).Custom((list, context) =>
{
if (list.Count > 10)
{
context.AddFailure("The list must contain 10 items or fewer");
// It allows you to return multiple errors for the same rule
context.AddFailure("SomeOtherProperty", "The list must contain 10 items or fewer");
// Or you can instantiate the ValidationFailure directly:
context.AddFailure(new ValidationFailure("SomeOtherProperty", "The list must contain 10 items or fewer");
}
});

3.Writing a Custom, reusable Property Validator 使用定制可重用属性验证器

//若定制的逻辑非常复杂,则可将定制逻辑放入单独的验证类中
public class ListCountValidator<T> : PropertyValidator
{
private int _max; public ListCountValidator(int max)
: base("{PropertyName} must contain fewer than {MaxElements} items.")
{
_max = max;
} protected override bool IsValid(PropertyValidatorContext context)
{
var list = context.PropertyValue as IList<T>; if (list != null && list.Count >= _max)
{
context.MessageFormatter.AppendArgument("MaxElements", _max);
return false;
} return true;
}
}
//调用方法一
RuleFor(person => person.Pets).SetValidator(new ListCountValidator<Pet>(10)); //调用方法二
public static IRuleBuilderOptions<T, IList<TElement>> ListMustContainFewerThan3<T, TElement>(this IRuleBuilder<T, IList<TElement>> ruleBuilder, int num)
{
return ruleBuilder.SetValidator(new ListCountValidator<Pet>(10));
}
RuleFor(x => x.Pets).ListMustContainFewerThan(10);

4.Using AbstractValidator.Custom (Deprecated in 7.0) 抽象验证器(弃用)

//从7.0版本开始弃用,推荐上文中使用的 RuleFor(x => x).Custom((x, context) => ... )
public class PersonValidator : AbstractValidator<Person>
{
public PersonValidator()
{
Custom(person => {
return person.Pets.Count >= 10
? new ValidationFailure("Pets", "More than 9 pets is not allowed.")
: null;
});
}
}

FluentValidation:C#后端输入验证框架的官方文档解读的更多相关文章

  1. Cuda 9.2 CuDnn7.0 官方文档解读

    目录 Cuda 9.2 CuDnn7.0 官方文档解读 准备工作(下载) 显卡驱动重装 CUDA安装 系统要求 处理之前安装的cuda文件 下载的deb安装过程 下载的runfile的安装过程 安装完 ...

  2. 【Java架构:基础技术】一篇文章搞掂:Spring Boot 官方文档解读

    本文篇幅较长,建议合理利用右上角目录进行查看(如果没有目录请刷新). 本文内容大部分是翻译和总结官方文档,可以到https://docs.spring.io/spring-boot/docs查看(此地 ...

  3. Axon 3.0.x 框架简介官方文档

    因为需要用到,但是在网上对应的资料实在是很少,只有迎着头皮看官网文档并配合翻译器.如有误导多多包涵. Axon 什么是 Axon Axon Framework 通过支持开发人员应用命令查询责任隔离(C ...

  4. 微信小程序开发官方文档解读

    创建页面 在这个教程里,我们有两个页面,index 页面和 logs 页面,即欢迎页和小程序启动日志的展示页,他们都在 pages 目录下.微信小程序中的每一个页面的[路径+页面名]都需要写在 app ...

  5. Python 官方文档解读(1):66 个内置函数

    Python 解释器 (CPython 3.7)内置有 66 个函数,这些函数在任何时刻都是可用的.此文是为了对这 66 个函数进行简单的梳理,便于以后可能用到它们时能想到. 1. abs(x) 返回 ...

  6. Android外部存储 - 官方文档解读

    预备知识:External Storage Technical Information 摘要: "The WRITE_EXTERNAL_STORAGE permission must onl ...

  7. Python 官方文档解读(2):threading 模块

    使用 Python 可以编写多线程程序,注意,这并不是说程序能在多个 CPU 核上跑.如果你想这么做,可以看看关于 Python 并行计算的,比如官方 Wiki. Python 线程的主要应用场景是一 ...

  8. 《SpringCloudDubbo开发日记》(一)Nacos连官方文档都没写好

    背景 现在的微服务框架一般分dubbo和springcloud两套服务治理体系,dubbo是基于zookeeper为注册中心,springcloud是基于eureka作为注册中心. 但是现在eurek ...

  9. 【pytest官方文档】解读fixtures - 1.什么是fixtures

    在深入了解fixture之前,让我们先看看什么是测试. 一.测试的构成 其实说白了,测试就是在特定的环境.特定的场景下.执行特定的行为,然后确认结果与期望的是否一致. 就拿最常见的登录来说,完成一次正 ...

随机推荐

  1. ASP入门(十七)-ASP #include

    通过使用 #include 指令,您可以在服务器执行 ASP 文件之前,把另一个 ASP 文件的内容插入到这个 ASP 文件中. 如何使用 #include 指令 这里有一个名为 mypage.asp ...

  2. 【Python】将对象存成json文件及从json取出对象

    常用代码,单拎出来以备查. 对象存json文件: import json obj={'name':'张有财','age':39,'arr':[2,34,5,6,7,88,'李有钱']} with op ...

  3. linux 常用命令--------雪松整理

    linux 常用命令--------雪松整理 博客: http://hi.baidu.com/quanzhou722/blog错误在所难免,还望指正!========================= ...

  4. 一家VC支持企业的发展轨迹——了解每次融资后股权和期权的变化,以及股份是如何被稀释的【转载】

    来源:ReachVc 该文是 ReachVC 上一篇文章,是某个投资公司副总裁的独立博客,文章写得不错.如果你是一个不太了解融资的创业者,那么本文将对你很有用.通过武林外传同福客栈的例子,了解每次融资 ...

  5. SQL Server 中断开连接到指定数据库的所有连接

    常用的情形是在部署测试数据库时需要通过SQL代码自动重新创建数据库,在删除的时候往往会发生错误,错误信息一般会指出目前有用户连接到这个数据库上,因此不能删除. 实现的方式是通过查询指定数据库中活跃的 ...

  6. Ubuntu Server无法安装busybox-initramfs

    解决方法很简单,使用英文安装就好,可以参考这个帖子:http://forum.ubuntu.com.cn/viewtopic.php?f=77&t=471547&p=3137632  

  7. Vue项目的npm环境搭建

    Vue项目的环境搭建主要步骤如下: vue项目创建 安装NodeJS +到官网下载自己系统对应的版本,这里我们下载Windows系统的64位zip文件,下载完成后解压,可以看到里面有一个node.ex ...

  8. CentOS 6.9 下安装DB2

    操作系统:CentOS6.9_x64 DB2安装文件: db2_v101_linuxx64_expc.tar.gz 安装数据库 tar zxvf db2_v101_linuxx64_expc.tar. ...

  9. system.DateTime ToDateTime(System.String)”,因此该方法无法转换为存储表达式-解决方法

    LINQ to Entities的lambda表达式中如果需要转换时间及各种时间格式请使用System.Data.Entity的类DbFunctions的各种方法 例如: IsOverdue = db ...

  10. java base64编码、解码的三种方式

      java base64编码.解码 CreationTime--2018年7月24日10点38分 Author:Marydon 1.方式一:DatatypeConverter 说明:使用jdk自带的 ...