首页/新闻资讯/正文详情

FluentValidation 入门实战:从第一个验证器到复杂属性验证

发布时间:2026/9/24 14:00:33 来源:云帆数科 栏目:资讯中心
FluentValidation 入门实战:从第一个验证器到复杂属性验证
后端【免费下载链接】FluentValidationA popular .NET validation library for building strongly-typed validation rules.项目地址https://gitcode.com/gh_mirrors/fl/FluentValidation点击查看免费下载导读本文基于 FluentValidation 官方入门文档docs/start.md带你从零创建一个强类型验证器先通过AbstractValidatorT与RuleFor定义规则再调用Validate获取ValidationResult处理错误随后深入链式验证、ValidateAndThrow异常抛出以及通过SetValidator复用子验证器验证复杂属性。文末结合当前仓库的 AbstractValidator.cs、ValidationResult.cs、ValidationStrategy.cs 等源码揭示每一步背后的底层实现原理帮助你在实际项目中写出严谨、可维护的验证逻辑。创建你的第一个验证器FluentValidation 采用验证器Validator与业务对象分离的设计要为某个对象定义一组验证规则你需要创建一个继承自AbstractValidatorT的类其中T就是要验证的对象类型。假设你有一个Customer类public class Customer { public int Id { get; set; } public string Surname { get; set; } public string Forename { get; set; } public decimal Discount { get; set; } public string Address { get; set; } }通过继承AbstractValidatorCustomer来定义它的验证器using FluentValidation; public class CustomerValidator : AbstractValidatorCustomer { }验证规则本身应当写在验证器类的构造函数中。构造函数会在验证器实例化时执行通过流式 API 把一条条规则注册到内部规则集合里。要针对某个属性指定验证规则调用RuleFor方法并传入一个指示待验证属性的 lambda 表达式。例如要确保Surname不为 null验证器写成using FluentValidation; public class CustomerValidator : AbstractValidatorCustomer { public CustomerValidator() { RuleFor(customer customer.Surname).NotNull(); } }从源码看RuleFor的定义位于 AbstractValidator.cs它把 lambda 表达式交给PropertyRuleT, TProperty.Create解析成一条内部规则添加到Rules集合并返回一个RuleBuilder供后续链式调用。也就是说构造函数中每写一条RuleFor就相当于向验证器注册了一条待执行规则验证器还实现了IEnumerableIValidationRule因此可以直接遍历它持有的全部规则。运行验证Validate 方法与 ValidationResult定义好验证器后实例化它并调用Validate方法传入要验证的对象即可执行验证Customer customer new Customer(); CustomerValidator validator new CustomerValidator(); ValidationResult result validator.Validate(customer);Validate返回一个ValidationResult对象其中包含两个核心属性IsValid—— 布尔值表示验证是否成功。Errors—— 一组ValidationFailure对象包含所有验证失败的详细信息。IsValid的实现非常直观见 ValidationResult.csErrors.Count 0即验证成功。Errors集合中的每个ValidationFailure都携带丰富信息除PropertyName属性名与ErrorMessage错误消息外还包含AttemptedValue导致失败的值、CustomState自定义状态、Severity严重级别默认Severity.Error与ErrorCode错误码完整定义见 ValidationFailure.cs。下面的代码会把所有验证失败信息输出到控制台using FluentValidation.Results; Customer customer new Customer(); CustomerValidator validator new CustomerValidator(); ValidationResult results validator.Validate(customer); if(! results.IsValid) { foreach(var failure in results.Errors) { Console.WriteLine(Property failure.PropertyName failed validation. Error was: failure.ErrorMessage); } }将错误合并为字符串ToStringValidationResult还重写了ToString可以把所有错误消息合并成单个字符串。默认使用换行符分隔各条消息如果你想自定义分隔符可以向ToString传入一个分隔字符ValidationResult results validator.Validate(customer); string allMessages results.ToString(~); // In this case, each message will be separated with a ~源码层面ToString()无参重载委托给ToString(Environment.NewLine)最终通过string.Join(separator, _errors.Select(failure failure.ErrorMessage))拼接见 ValidationResult.cs。注意如果没有验证错误ToString()会返回一个空字符串。另外ValidationResult还提供ToDictionary()方法将错误按属性名分组返回IDictionarystring, string[]便于在 API 层直接序列化或绑定到表单错误上。链式验证一条规则串联多个约束你可以针对同一个属性把多个验证器链在一起每个验证器按书写顺序依次执行using FluentValidation; public class CustomerValidator : AbstractValidatorCustomer { public CustomerValidator() { RuleFor(customer customer.Surname).NotNull().NotEqual(foo); } }这条链式规则同时确保Surname不为 null且不等于字符串foo。链式调用的机制在于RuleFor返回的IRuleBuilder上挂载了一系列内置验证器扩展方法.NotNull()、.NotEqual()、.Length()、.EmailAddress()等每个方法都会把一个新的验证器组件追加到当前规则上并返回构建器本身以继续链式调用。仓库中的内置验证器分布在 src/FluentValidation/Validators 目录下例如 NotNullValidator.cs、EqualValidator.cs。需要说明的是链式验证属于**规则内部rule-level**的级联行为默认情况下同一条链上的验证器无论前一个是否失败都会全部执行若希望同一条链上某个验证器失败后立即停止后续验证器可通过级联模式CascadeMode配置相关机制详见 cascade.md。抛出异常ValidateAndThrow前面使用Validate时验证失败只会体现在返回的ValidationResult中并不会中断程序。如果你希望在验证失败时直接抛出异常可以使用ValidateAndThrow方法Customer customer new Customer(); CustomerValidator validator new CustomerValidator(); validator.ValidateAndThrow(customer);当验证失败时它会抛出一个ValidationException该异常通过Errors属性携带全部错误消息异常类型定义见 ValidationException.cs其Errors为IEnumerableValidationFailure。注意ValidateAndThrow是一个扩展方法因此文件顶部必须用using FluentValidation;引入命名空间该方法才可用。同步版本ValidateAndThrow与异步版本ValidateAndThrowAsync都定义在 DefaultValidatorExtensions_Validate.cs 中。底层等价写法Options APIValidateAndThrow本质上是 FluentValidation Options API 的一个便捷封装等价于validator.Validate(customer, options options.ThrowOnFailures());ThrowOnFailures()定义于 ValidationStrategy.cs它会设置内部_throw标志使得Validate执行完毕后若结果无效便抛出异常。如果需要在抛异常的同时组合使用 Rule Sets规则集或只验证指定属性可以通过 Options 语法同时配置多个选项validator.Validate(customer, options { options.ThrowOnFailures(); options.IncludeRuleSets(MyRuleSets); options.IncludeProperties(x x.Name); });这里用到的三个关键方法都来自ValidationStrategyTThrowOnFailures()验证失败时抛异常IncludeRuleSets(MyRuleSets)仅执行指定规则集中的规则IncludeProperties(x x.Name)仅验证指定属性。ValidationStrategy还提供IncludeAllRuleSets()相当于*执行所有规则、IncludeRulesNotInRuleSet()相当于default只执行不在规则集中的规则和UseCustomSelector(...)使用自定义选择器等高级选项。当多个选项同时出现时内部会将对应的MemberNameValidatorSelector、RulesetValidatorSelector组合成CompositeValidatorSelector一起生效。仓库中的测试 ValidateAndThrowTester.cs 验证了相关行为验证失败时抛出ValidationException、携带错误信息、验证成功时不抛出异常以及规则集与ValidateAndThrowAsync的组合场景。自定义异常类型ValidateAndThrow默认抛出ValidationException。如果需要每次抛出特定类型的自定义异常可以通过在验证器中重写RaiseValidationException方法实现具体做法见 自定义验证异常。复杂属性复用子验证器验证器可以针对复杂属性进行复用。假设有两个类Customer和Addresspublic class Customer { public string Name { get; set; } public Address Address { get; set; } } public class Address { public string Line1 { get; set; } public string Line2 { get; set; } public string Town { get; set; } public string Country { get; set; } public string Postcode { get; set; } }先为Address定义一个AddressValidatorpublic class AddressValidator : AbstractValidatorAddress { public AddressValidator() { RuleFor(address address.Postcode).NotNull(); //etc } }然后在CustomerValidator中通过SetValidator复用它public class CustomerValidator : AbstractValidatorCustomer { public CustomerValidator() { RuleFor(customer customer.Name).NotNull(); RuleFor(customer customer.Address).SetValidator(new AddressValidator()); } }这样当调用CustomerValidator的Validate时会依次执行CustomerValidator与AddressValidator中定义的所有规则并把两部分的失败信息合并到同一个ValidationResult中返回。子属性为 null 时的行为如果子属性为 null则子验证器不会执行。这一行为在源码 ChildValidatorAdaptor.cs 中清晰可见IsValid方法第一步就是if (value null) return true;即属性值为 null 时直接跳过子验证器。RuleBuilder.SetValidator(IValidatorTProperty)见 RuleBuilder.cs内部会把这个子验证器包装成ChildValidatorAdaptor并注册到规则中同时它天然支持同步与异步执行。替代方案内联子规则除了使用子验证器你也可以直接内联定义子属性规则RuleFor(customer customer.Address.Postcode).NotNull()注意这种写法不会自动对Address执行 null 检查——属性表达式直接穿透到了Address.Postcode。如果Address为 null访问Postcode会引发空引用问题因此需要显式添加条件RuleFor(customer customer.Address.Postcode).NotNull().When(customer customer.Address ! null).When(...)接收一个谓词只有谓词返回 true 时才执行该规则Address不为 null 时才校验Postcode。与之对应的否定形式是.Unless(...)谓词为 false 时执行。两者的实现同样位于 AbstractValidator.cs 中。延伸从源码看验证执行链路Validate 的完整流程AbstractValidator.cs 中Validate(T instance)会构造一个ValidationContextT然后进入ValidateInternal先调用PreValidate钩子再遍历Rules集合逐条执行当某条规则产生失败且验证器的ClassLevelCascadeMode CascadeMode.Stop时会提前终止后续规则快速失败。此外传入 null 模型会抛出InvalidOperationException提示根模型不能为 null。同步遍历规则时若遇到异步验证器会抛出AsyncValidatorInvokedSynchronouslyException提醒开发者改用ValidateAsync。异步验证对于包含MustAsync、SetValidator等异步验证器的场景应使用ValidateAsync见 AbstractValidator.cs它接受一个CancellationToken并会逐条执行规则的异步版本ValidationResult result await validator.ValidateAsync(customer, cancellationToken);注意ValidateAsync与Validate是两条独立的执行路径同步调用无法执行异步规则反之亦然请根据实际规则类型选择对应入口。级联模式CascadeModeAbstractValidatorT暴露了ClassLevelCascadeMode规则之间与RuleLevelCascadeMode单条规则内部两个可配置属性默认值分别取自ValidatorOptions.Global.DefaultClassLevelCascadeMode与DefaultRuleLevelCascadeMode见 AbstractValidator.cs。Continue表示无论是否失败都继续执行Stop表示失败即停止这是控制失败后短路行为的关键开关详见 cascade.md。小结通过本文你已经掌握了 FluentValidation 的完整入门链路用AbstractValidatorT定义验证器在构造函数中用RuleFor lambda 声明属性规则调用Validate得到ValidationResult通过IsValid/Errors检查结果用ToString/ToDictionary汇总错误用链式调用对同一属性叠加多个约束用ValidateAndThrow及其 Options API 等价形式在失败时抛出ValidationException用SetValidator复用子验证器验证复杂属性并注意子属性为 null 时的自动跳过与内联规则下需要手动添加When条件。以上示例代码均可直接复制运行。若要继续深入可依次阅读仓库中的 custom-validators.md、built-in-validators.md、collections.md 与 testing.md 等文档。赞分享后端【免费下载链接】FluentValidationA popular .NET validation library for building strongly-typed validation rules.项目地址https://gitcode.com/gh_mirrors/fl/FluentValidation点击查看免费下载相关推荐FluentValidation入门指南创建第一个验证器FluentValidation入门指南创建第一个验证器 什么是FluentValidation FluentValidation是一个流行的.NET验证库后端搞定复杂数据验证FluentValidation对象与集合校验实战搞定复杂数据验证FluentValidation对象与集合校验实战 你还在为嵌套表单数据校验抓狂用户提交的订单列表总是包含无效商品本文将带你掌握Fluen后端快速上手FluentValidation从零构建你的第一个验证器的完整教程快速上手FluentValidation从零构建你的第一个验证器的完整教程 FluentValidation 是一款广受欢迎的 .NET 验证库它通过流式接后端上一篇Fedora-Hyprland性能优化技巧让你的Hyprland桌面运行如飞下一篇Ytt 集成开发指南如何将模板引擎嵌入你的 Go 应用创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关推荐

it 的几种用法
it 的几种用法

开篇:一个词,六种身份看这六个句子,每个都有 it,但意思完全不同: ① I bought a book. It is interesting. ← it 那本书 ② It is raining. ← it 什么都不指 ③ It is hard to… · 2026/9/24 14:00:33

Lambda表达式详解
Lambda表达式详解

Kotlin Lambda 表达式详解 参考来源:Kotlin——高级篇(一):Lambda表达式详解 一、Lambda 介绍 Lambda 表达式本质是匿名函数,底层通过匿名函数实现。它是函数式编程的基础,能让代码更简洁。 直观对比&… · 2026/9/24 14:00:33

如何用 SDR++ 免费收听全频段无线电:软件定义无线电新手完整上手指南
如何用 SDR++ 免费收听全频段无线电:软件定义无线电新手完整上手指南

如何用 SDR 免费收听全频段无线电:软件定义无线电新手完整上手指南 【免费下载链接】SDRPlusPlus Cross-Platform SDR Software 项目地址: https://gitcode.com/GitHub_Trending/sd/SDRPlusPlus SDR(SDR Plus Plus)是一款免费、开源、… · 2026/9/24 14:00:27

中兴B862AV3.2-M变砖救砖教程:免拆机免开ADB,双公头线完美刷回
中兴B862AV3.2-M变砖救砖教程:免拆机免开ADB,双公头线完美刷回

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/24 14:27:42

稻百年研学赋能|百余位企业家齐聚,共探企业经营增长之路
稻百年研学赋能|百余位企业家齐聚,共探企业经营增长之路

2026年9 月 21 日 —24 日,稻百年企业家研学活动顺利举办,全国 132 位企业经营者参与学习,118 人全程参加,山东裕邦食品集团 14 名高管专项参加 23 日课程。本次研学聚焦组织建设、团队赋能、企业文化落地等课题,吸引服… · 2026/9/24 14:27:42

让 AutoValue 类真正可序列化:SerializableAutoValueExtension 扩展机制全解析
让 AutoValue 类真正可序列化:SerializableAutoValueExtension 扩展机制全解析

代码生成开发工具 【免费下载链接】auto A collection of source code generators for Java. 项目地址: https://gitcode.com/gh_mirrors/auto/auto 点击查看 免费下载 SerializableAutoValueExtension 是 Google Auto 项目中为 AutoValue 打造的序列化扩展&#x… · 2026/9/24 14:27:42

Flink CDC OceanBase CDC 连接器实战指南:全量+增量实时同步怎么做
Flink CDC OceanBase CDC 连接器实战指南:全量+增量实时同步怎么做

Flink CDC OceanBase CDC 连接器实战指南:全量增量实时同步怎么做 【免费下载链接】flink-cdc Flink CDC is a streaming data integration tool 项目地址: https://gitcode.com/GitHub_Trending/flin/flink-cdc Flink CDC OceanBase CDC 连接器是 Flink CDC… · 2026/9/24 14:27:42

553 个种子站一次搜完:Jackett 聚合索引器完整使用指南
553 个种子站一次搜完:Jackett 聚合索引器完整使用指南

553 个种子站一次搜完:Jackett 聚合索引器完整使用指南 想追一部新剧,得在十几个资源站之间来回切:逐个登录、逐个输词、逐个比种子数。Jackett 是跑在本地的搜索中转:替你查 553 个站,把结果整理成统一格式,交给 Sonarr、Radarr 这类软件直接用。 📦 先把它跑起来… · 2026/9/24 14:27:42

基于大模型与AI的泵阀品控溯源系统设计实践
基于大模型与AI的泵阀品控溯源系统设计实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/24 14:27:36

基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程
基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程

简介:这是一套面向计算机、人工智能、自动化等专业学生与教师的毕业设计级项目资源,围绕YOLOv8实现渔船作业监控系统,可用于毕设、课程设计、大作业或项目立项演示。压缩包共97个文件,约24.21MB,以70个Python源码文件为… · 2026/9/24 0:00:13

1D-CNN时间序列建模实战:从Conv1d原理到工业落地
1D-CNN时间序列建模实战:从Conv1d原理到工业落地

简介:面向时间序列数据建模的一维卷积神经网络完整实现,适合深度学习入门者及需要快速验证时序模型的研究者,能够从音频、文本、传感器或股价等序列中挖掘局部特征与时间依赖。压缩包体积很小,只有3KB,内含3个Python脚… · 2026/9/24 0:00:26

柔软的L:汉语语流中被忽视的舌肌张力控制
柔软的L:汉语语流中被忽视的舌肌张力控制

1. 这个“L”不是字母表里的L,而是舌尖上的L最近在几个方言群和语音教学社群里,反复看到有人发一句:“也说字母L:柔软的长舌”。初看以为是英语发音课笔记,点开才发现全是方言爱好者、播音系学生、语言康复师甚至戏曲演… · 2026/9/24 0:00:44

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码