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 阅读更多 →
拆解 ROCm 文档仓库:官方文档站背后的 3 条数据流水线与 changelog 自动化

拆解 ROCm 文档仓库:官方文档站背后的 3 条数据流水线与 changelog 自动化

拆解 ROCm 文档仓库:官方文档站背后的 3 条数据流水线与 changelog 自动化 【免费下载链接】legacy-rocm-build AMD ROCm™ Software - GitHub Home 项目地址: https://gitcode.com/GitHub_Trending/ro/legacy-rocm-build 导读 这个仓库是 ROCm 文档站&…

2026/9/24 13:59:32 阅读更多 →
Apache Pulsar 与 Spark Streaming 集成实战:基于 SparkStreamingPulsarReceiver 构建实时流处理应用

Apache Pulsar 与 Spark Streaming 集成实战:基于 SparkStreamingPulsarReceiver 构建实时流处理应用

消息队列后端流处理 【免费下载链接】pulsar Apache Pulsar - distributed pub-sub messaging system 项目地址: https://gitcode.com/gh_mirrors/pulsar28/pulsar 点击查看 免费下载 导读 本文围绕 Apache Pulsar 官方文档中关于 Spark Streaming 适配器的核心内…

2026/9/24 13:59:32 阅读更多 →

最新新闻

伺服系统抖动归因:电气、机械与控制三维度诊断框架

伺服系统抖动归因:电气、机械与控制三维度诊断框架

/* 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:47:00 阅读更多 →
Sonnet 2 开发指南:基于 TensorFlow 2 的模块化神经网络库核心用法与序列化实战

Sonnet 2 开发指南:基于 TensorFlow 2 的模块化神经网络库核心用法与序列化实战

深度学习机器学习 【免费下载链接】sonnet TensorFlow-based neural network library 项目地址: https://gitcode.com/gh_mirrors/so/sonnet 点击查看 免费下载 Sonnet 是 DeepMind 设计并构建、运行在 TensorFlow 2 之上的神经网络库,其核心目标是提供…

2026/9/24 14:47:00 阅读更多 →
easing-functions-cj API 参考大全:Skill 枚举、getMethod() 与 calculate() 每个参数逐条精讲

easing-functions-cj API 参考大全:Skill 枚举、getMethod() 与 calculate() 每个参数逐条精讲

easing-functions-cj API 参考大全:Skill 枚举、getMethod() 与 calculate() 每个参数逐条精讲 【免费下载链接】easing-functions-cj 一个基于缓动函数的动画UI组件库 项目地址: https://gitcode.com/Cangjie-TPC/easing-functions-cj easing-functions-cj …

2026/9/24 14:47:00 阅读更多 →
PDF 补丁丁:免费编辑 PDF 书签、合并文档与解除限制的完整指南

PDF 补丁丁:免费编辑 PDF 书签、合并文档与解除限制的完整指南

PDF 补丁丁:免费编辑 PDF 书签、合并文档与解除限制的完整指南 【免费下载链接】PDFPatcher PDF补丁丁——PDF工具箱,可以编辑书签、剪裁旋转页面、解除限制、提取或合并文档,探查文档结构,提取图片、转成图片等等 项目地址: ht…

2026/9/24 14:47:00 阅读更多 →
EasyWeChat 3.x 用户分组(User Group)管理实战:获取、增删改查与批量移动用户完整 API 指南

EasyWeChat 3.x 用户分组(User Group)管理实战:获取、增删改查与批量移动用户完整 API 指南

后端即时通讯 【免费下载链接】easywechat 📦 一个 PHP 微信 SDK 项目地址: https://gitcode.com/gh_mirrors/ea/easywechat 点击查看 免费下载 导读 用户分组是微信公众号后台用户管理的基础能力之一,用于按自定义维度(如地区、…

2026/9/24 14:47:00 阅读更多 →
手把手教你用 tchMaterial-parser 批量下载智慧教育平台电子课本 PDF

手把手教你用 tchMaterial-parser 批量下载智慧教育平台电子课本 PDF

手把手教你用 tchMaterial-parser 批量下载智慧教育平台电子课本 PDF 【免费下载链接】tchMaterial-parser 国家中小学智慧教育平台 电子课本下载工具,帮助您从智慧教育平台中获取电子课本的 PDF 文件网址并进行下载,让您更方便地获取课本内容。 项目地…

2026/9/24 14:46:00 阅读更多 →

日新闻

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

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

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

2026/9/24 0:00:19 阅读更多 →
单细胞注释实战:基于Scanpy的标记基因与参考映射流程解析

单细胞注释实战:基于Scanpy的标记基因与参考映射流程解析

简介:一份基于单细胞RNA测序数据的细胞类型注释算法研究Python毕业设计源码,针对计算机相关专业正在做毕设或需要项目实战的学习者,可用于课程设计与期末大作业。项目代码完整、经导师指导评审通过,可直接运行,覆盖数据…

2026/9/24 0:00:19 阅读更多 →
C#源生成器实战:用增量生成器替代反射,告别AOT崩溃

C#源生成器实战:用增量生成器替代反射,告别AOT崩溃

第一次在项目里被反射卡住,是在一个老旧的WinForms模块里:几十个类依赖PropertyChanged通知,运行时反射读属性、发通知,每次启动慢半拍不说,一上.NET Native/AOT裁剪模式几乎全面崩盘。后来我把这段逻辑全部改成C#源生…

2026/9/24 0:00:19 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/24 14:34:13 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/24 9:10:42 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/24 14:33:56 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/24 12:50:34 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/24 14:33:48 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/24 12:49:17 阅读更多 →