Asp.net core 学习笔记 Fluent Validation
2020-02-20
NotEmpty vs NotNull
public class SimpleTestData
{
public string? string1 { get; set; }
public string string2 { get; set; } = "";
public int? number1 { get; set; }
public int numbe2 { get; set; }
}
json
{
"string1" : "",
"string2" : "",
"number1" : 0,
"number2" : 0
}
result
"errors": {
"numbe2": [
"'numbe2' must not be empty."
],
"string1": [
"'string1' must not be empty."
],
"string2": [
"'string2' must not be empty."
]
}
int 如果是 nullable 的话, empty 只是验证 != null, 0 是 ok 的, 因为 default(int?) 是 null. 符合逻辑.
int 如果不是 nullable, empty 验证 != 0 因为 default(int) 是 0
但是 string 就不同了, 因为没有初始值, 所以 emptty 永远都会检查 "" empty string. 所以这个时候用 notnull 就比较合理了.
not empty 对 List<string> length = 0 也是会保护哦
2020-02-04
InclusiveBetween vs ExclusiveBetween
between 1 - 10, 没有说明 1 和 10 是不是 ok. (大部分情况下是)
如果 1 和 10 ok 那么就是 InclusiveBetween
如果是 1 和 10 不可以, 2...9 才可以的话,那么是 ExclusiveBetween
2019-10-24
新功能,child validation
从前需要特地开一个 child validator 来写逻辑, 现在不需要咯
public class CustomerValidator : AbstractValidator<Customer> {
public CustomerValidator() {
RuleForEach(x => x.Orders).ChildRules(order => {
order.RuleFor(x => x.ProductName).NotNull();
order.RuleFor(x => x.Amount).GreaterThan();
});
}
}
2019-08-18
验证 decimal scale 和 precision
RuleFor(x => x.Amount).ScalePrecision(4, 9);
留意哦,1st param 是 scale 2nd 才是 precision
和 sql 是相反的. sql 是 decimal(9,4), 真奇葩...
issue : https://github.com/JeremySkinner/FluentValidation/issues/1008
目前它的验证也和 sql 不同, 比如 decimal(9, 4), 意思是前面最多 5 位数. 但是 fluent validation 没有左右验证的概念. 所以这个是通过的,然后你输入 sql 就会报错了.
作者说 9.0 可能修改这个. 让它和 sql 验证行为一致.
之前就有在 .net 时代介绍过了.
这个 dll 也支持 .net core 而且一直有人维护.
对比 data annotation 的 validation, 我越来越觉得这个 fluent 好用多了.
一堆 Attribute 在 property 上面真的很乱.
安装很容易
nuget : https://www.nuget.org/packages/FluentValidation.AspNetCore/
然后 startup.cs
services.AddMvc().AddFluentValidation(fvc => fvc.RegisterValidatorsFromAssemblyContaining<Startup>()).SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
定义规则 : getting started refer : https://fluentvalidation.net/start
public class ProductPostData
{
public string code { get; set; }
} public class ProductPostDataValidator : AbstractValidator<ProductPostData>
{
public ProductPostDataValidator()
{
RuleFor(product => product.code).NotEmpty();
}
}
build in rule :
https://fluentvalidation.net/built-in-validators
complex 的做法 :
写一个 child validator, 然后 SetValidator. 一定要 set 哦, 不会自动的
RuleFor(o => o.Address).NotNull();
RuleFor(o => o.Address).SetValidator(new AddressValidator());
或者直接定义, 不过要记得另外处理 null 的情况哦, 还有一般的 If
RuleFor(o => o.Address).NotNull();
RuleFor(o => o.Address.text1).NotEmpty().When(o => o.Address != null);
也可以 if else 包起来
When(customer => customer.IsPreferred, () => {
RuleFor(customer => customer.CustomerDiscount).GreaterThan();
RuleFor(customer => customer.CreditCardNumber).NotNull();
}).Otherwise(() => {
RuleFor(customer => customer.CustomerDiscount).Equal();
});
这个很常用到 .Must()
refer : https://fluentvalidation.net/custom-validators#predicate-validator
custom valid
https://fluentvalidation.net/custom-validators
namespace Project.Validators
{
public static class CustomValidatorExtensions
{
public static IRuleBuilderOptions<T, string> IsKeatKeat<T>(
this IRuleBuilder<T, string> ruleBuilder, string value)
{ return ruleBuilder.Must((rootObject, propertyValue, context) =>
{
context.MessageFormatter.AppendArgument("value", value);
return (propertyValue as string) == "keatkeat";
}).WithMessage("{PropertyValue} is not keatkeat {value}"); //return ruleBuilder.SetValidator(new IsKeatKeatValidator(value));
}
} public class IsKeatKeatValidator : PropertyValidator
{
private readonly string Value;
public IsKeatKeatValidator(string value)
: base("{PropertyValue} is not keatkeat {value}")
{
Value = value;
}
protected override bool IsValid(PropertyValidatorContext context)
{
if (context.PropertyValue == null) return false;
var propertyValue = context.PropertyValue as string;
context.MessageFormatter.AppendArgument("value", Value);
return propertyValue == "keatkeat";
}
}
}
RuleFor(p => p.code).NotEmpty().IsKeatKeat("keatkeat");
DI 和 async
public ProductPostDataValidator(
ApplicationDbContext Db
)
{
//RuleFor(p => p.code).NotEmpty().IsKeatKeat("keatkeat");
RuleFor(p => p.code).NotEmpty().MustAsync(async (id, cancellation) =>
{
var products = await Db.Products.ToListAsync();
return true;
});
}
如果用 setValidator 那就要自己传进去了。
多一个例子, 不用匿名方法
public class SimpleTestDataValidator : AbstractValidator<SimpleTestData>
{
private readonly IHttpContextAccessor HttpContextAccessor;
public SimpleTestDataValidator(
IHttpContextAccessor httpContextAccessor
)
{
HttpContextAccessor = httpContextAccessor;
RuleFor(p => p.age).NotEmpty().MustAsync(BeSomething);
} private async Task<bool> BeSomething(int age, CancellationToken cancellation)
{
await Task.Delay();
return true;
}
}
array, not empty 就是 check null 和 count, 通过 foreach set 后面的
RuleFor(p => p.colors).NotEmpty().ForEach(c => c.SetValidator(new ProductColorPostDataValidator()));
错一个就停 CascadeMode, defualt 行为是会验证所有的错误.
refer https://fluentvalidation.net/start#setting-the-cascade-mode#setting-the-cascade-mode
RuleFor(p => p.age).NotEmpty();
RuleFor(p => p.age).Cascade(CascadeMode.StopOnFirstFailure).Must(BeSomething).MustAsync(BeSomethingAsync);
DependentRules 这个也是用于错就不要跑接下来的
RuleFor(p => p.name).NotEmpty();
RuleFor(p => p.datas).NotEmpty().DependentRules(() =>
{
RuleForEach(p => p.datas).SetValidator(new DataValidator()).DependentRules(() =>
{
RuleFor(p => p.datas).Must(v => false);
});
});
也可以针对整个 validator
public class PersonValidator : AbstractValidator<Person> {
public PersonValidator() {
// First set the cascade mode
CascadeMode = CascadeMode.StopOnFirstFailure; RuleFor(x => x.Surname).NotNull().NotEqual("foo");
RuleFor(x => x.Forename).NotNull().NotEqual("foo");
}
}
甚至是全局 ( 注意这个是 static 属性来的,不需要通过 config options 来配置 )
ValidatorOptions.CascadeMode = CascadeMode.StopOnFirstFailure;
Asp.net core 学习笔记 Fluent Validation的更多相关文章
- Asp.Net Core学习笔记:入门篇
Asp.Net Core 学习 基于.Net Core 2.2版本的学习笔记. 常识 像Django那样自动检查代码更新,自动重载服务器(太方便了) dotnet watch run 托管设置 设置项 ...
- ASP.NET Core 学习笔记 第一篇 ASP.NET Core初探
前言 因为工作原因博客断断续续更新,其实在很早以前就有想法做一套关于ASP.NET CORE整体学习度路线,整体来说国内的环境的.NET生态环境还是相对比较严峻的,但是干一行爱一行,还是希望更多人加入 ...
- Asp.net Core学习笔记
之前记在github上的,现在搬运过来 变化还是很大的,感觉和Nodejs有点类似,比如中间件的使用 ,努力学习ing... 优点 不依赖IIS 开源和跨平台 中间件支持 性能优化 无所不在的依赖注入 ...
- ASP.NET Core 学习笔记 第三篇 依赖注入框架的使用
前言 首先感谢小可爱门的支持,写了这个系列的第二篇后,得到了好多人的鼓励,也更加坚定我把这个系列写完的决心,也能更好的督促自己的学习,分享自己的学习成果.还记得上篇文章中最后提及到,假如服务越来越多怎 ...
- ASP.NET Core 学习笔记 第四篇 ASP.NET Core 中的配置
前言 说道配置文件,基本大多数软件为了扩展性.灵活性都会涉及到配置文件,比如之前常见的app.config和web.config.然后再说.NET Core,很多都发生了变化.总体的来说技术在进步,新 ...
- ASP.NET Core 学习笔记 第五篇 ASP.NET Core 中的选项
前言 还记得上一篇文章中所说的配置吗?本篇文章算是上一篇的延续吧.在 .NET Core 中读取配置文件大多数会为配置选项绑定一个POCO(Plain Old CLR Object)对象,并通过依赖注 ...
- Asp.net core 学习笔记 ( Data protection )
参考 : http://www.cnblogs.com/xishuai/p/aspnet-5-identity-part-one.html http://cnblogs.com/xishuai/p/a ...
- Asp.net core 学习笔记 SignalR
refer : https://kimsereyblog.blogspot.com/2018/07/signalr-with-asp-net-core.html https://github.com/ ...
- Asp.net core (学习笔记 路由和语言 route & language)
https://docs.microsoft.com/en-us/aspnet/core/mvc/controllers/routing?view=aspnetcore-2.1 https://doc ...
随机推荐
- c#十进制转二进制算法 和字符串反转算法
去某软面试 面试官给个题上黑板做,写个算法 求95转2进制后1的个数. 我在黑板上敲了 static int count = 0; /// <summary> /// 获取10进制数转2进 ...
- Pocket Gem OA: Path Finder
1. 有向图 找所有start node到end node之间的路径 输入是一个txt 形式如下: A E A : B C D. B : C C : E D : B. 输出一个List<Stri ...
- php curl 上传json数据
PUT $data = array('username'=>'dog','password'=>'tall'); $data_json = json_encode($data); $ch ...
- AL32UTF8 and UTF8 and ZHS16GBK
About AL32UTF8 ORACLE数据库字符集,即Oracle全球化支持(Globalization Support), 或即国家语言支持(NLS)其作用是用本国语言和格式来存储.处理和检索数 ...
- (转)Oracle EBS 有效银行账户取值 银行科目
SELECT ba.bank_account_id, --银行账户key ftv.territory_short_name, --国家 ftv.territory_code, --国家简称 cb.ba ...
- Promise的那些事儿
在JavaScript中,异步操作非常多见,然而在Promise之前,我们是在类似以下的做法中处理多重异步回调,每一层里都要调另一个异步函数,形成了所谓的"回调地狱", Promi ...
- 单片机C语言基础编程源码六则
1.某单片机系统的P2口接一数模转换器DAC0832输出模拟量,现在要求从DAC0832输出连续的三角波,实现的方法是从P2口连续输出按照三角波变化的数值,从0开始逐渐增大,到某一最大值后逐渐减小,直 ...
- Spring Configuration注解使用
@Configuration是spring.xml的注解版. @ComponentScan是<context:component-scan base-package="com.cosh ...
- redis-使用问题
记录一下相关的问题,使用参考http://www.runoob.com/redis/ 1.DENIED Redis is running in protected mode 这个是启用了保护模式,这个 ...
- Redis学习-持久化机制
Redis持久化的意义 在于故障恢复 比如你部署了一个redis,作为cache缓存,当然也可以保存一些较为重要的数据 如果没有持久化的话,redis遇到灾难性故障的时候(断电.宕机),就会丢失所有的 ...