后端【免费下载链接】FluentValidationA popular .NET validation library for building strongly-typed validation rules.项目地址https://gitcode.com/gh_mirrors/fl/FluentValidation点击查看免费下载导读本指南基于 FluentValidation 官方文档 docs/configuring.md系统讲解如何定制验证失败时生成的错误消息与属性名从最常用的WithMessage覆盖默认消息、占位符Placeholder机制到WithName/OverridePropertyName的差别再到集合校验时OverrideIndexer控制索引显示格式。读完本文你将能够为每个验证规则产出面向用户的可读错误提示并理解这些 API 在源码层面DefaultValidatorOptions.cs、MessageFormatter.cs、PropertyChain.cs是如何被实现和串联的。一、用 WithMessage 覆盖默认错误消息FluentValidation 的每个内置校验器都有默认的错误文案多数来自本地化资源详见 localization。当默认文案不符合业务需要时可以在规则链上调用WithMessage指定自定义消息RuleFor(customer customer.Surname).NotNull().WithMessage(Please ensure that you have entered your Surname);在源码层面WithMessage字符串重载定义于 DefaultValidatorOptions.cs它通过Configurable(rule).Current.SetErrorMessage(errorMessage)将自定义消息挂到紧随其后的那条规则组件上因此它只作用于链上直接相邻的校验器。例如NotNull().NotEmpty()之后调用WithMessage只会影响NotEmpty那一条。消息占位符机制自定义消息中可以嵌入{PropertyName}这类占位符运行时会被替换为实际值RuleFor(customer customer.Surname).NotNull().WithMessage(Please ensure you have entered your {PropertyName}); // 失败时输出Please ensure you have entered your Surname占位符的替换由 MessageFormatter.cs 完成BuildMessage内部用正则{([^{}:])(?::([^{}]))?}扫描消息模板并从PlaceholderValues字典中取值替换。值得一提的细节是正则中的第二个分组支持格式说明符即占位符可以写成{PropertyValue:0.00}这类带格式化字符串的形式最终通过string.Format({0:格式}, value)完成格式化见 MessageFormatter.cs。各类校验器支持的占位符所有校验器通用{PropertyName}—— 被验证属性的名称{PropertyValue}—— 被验证属性的值这两者同样适用于谓词校验器Must、邮箱校验器和正则校验器。比较类校验器Equal、NotEqual、GreaterThan、GreaterThanOrEqual、LessThan、LessThanOrEqual、ExclusiveBetween、InclusiveBetween等额外支持{ComparisonValue}—— 用于比较的值{ComparisonProperty}—— 被比较的属性名如果存在Length 校验器专用{MinLength}—— 最小长度{MaxLength}—— 最大长度{TotalLength}—— 用户实际输入的长度每个内置校验器支持哪些占位符的完整清单可查阅 built-in-validators 中对应校验器的说明。用 lambda 动态构造消息WithMessage还提供两个 lambda 重载DefaultValidatorOptions.cs可以引用被校验对象上的其他属性或常量值// 在消息中引用常量 RuleFor(customer customer.Surname) .NotNull() .WithMessage(customer string.Format(This message references some constant values: {0} {1}, hello, 5)) // 结果This message references some constant values: hello 5 // 引用对象上的其他属性字符串插值 RuleFor(customer customer.Surname) .NotNull() .WithMessage(customer $This message references some other properties: Forename: {customer.Forename} Discount: {customer.Discount}) // 结果This message references some other properties: Forename: Jeremy Discount: 100lambda 重载在实现上通过SetErrorMessage((ctx, val) ...)注册一个延迟执行的委托DefaultValidatorOptions.cs这意味着消息在验证失败时才求值而非定义规则时求值。注意WithMessage只会覆盖某一条规则的文案。如果你希望全局替换所有默认消息例如统一走公司内部的多语言资源应使用 FluentValidation 的本地化能力参考 localization。二、用 WithName 定制错误消息中的属性名默认错误消息会把被验证的属性名嵌入其中。例如RuleFor(customer customer.Surname).NotNull();失败时默认消息形如Surname must not be empty.。若只想替换消息里的属性名可调用WithNameRuleFor(customer customer.Surname).NotNull().WithName(Last name); // 失败时输出Last name must not be empty.测试用例 AbstractValidatorTester.cs 验证了这一点WithName(First Name)后Forename的 NotNull 失败消息为First Name must not be empty.WithName同样有 lambda 重载DefaultValidatorOptions.cs可动态计算显示名RuleFor(customer customer.Surname).NotNull().WithName(customer Last name for customer customer.Id);测试 AbstractValidatorTester.cs 展示了用WithName(x x.Surname)把显示名取自另一个属性的用法。WithName 与 OverridePropertyName 的区别WithName只影响消息中的显示名。当检查ValidationResult.Errors时该失败项仍关联到原始属性Surname——也就是说PropertyName、PropertyName路径、校验选择器validator selector等逻辑都照旧工作。OverridePropertyName则是完全重命名属性DefaultValidatorOptions.cs它直接改写规则底层记录的PropertyNameRuleFor(customer customer.Surname).NotNull().OverridePropertyName(foo);从源码看OverridePropertyName通过Configurable(rule).PropertyName propertyName设置规则属性名DefaultValidatorOptions.cs因此ValidationResult.Errors[0].PropertyName会变成foo见测试 AbstractValidatorTester.cs。它还有一个接收 lambda 表达式的重载会自动提取表达式中成员名RuleFor(customer customer.Surname).NotNull().OverridePropertyName(x x.Forename); // Errors[0].PropertyName Forename源码注释明确提醒OverridePropertyName属于高级特性大多数场景下你真正想要的是WithNameDefaultValidatorOptions.cs。另有使用场景当RuleFor无法从表达式推断属性名时例如对IEnumerable调用RuleForEach需要显式调用OverridePropertyName否则运行时会抛出 Could not infer property name... 异常该异常消息可见于测试 ForEachRuleTests.cs。全局可插拔的显示名解析器属性显示名的解析逻辑本身是可替换的。默认情况下FluentValidation 从传入RuleFor的MemberExpression中提取成员名其默认实现是ValidatorConfiguration.DefaultDisplayNameResolver返回 null从而回退到成员名见 ValidatorOptions.cs 与 DefaultValidatorExtensions.cs。你可以通过ValidatorOptions.Global.DisplayNameResolver全局修改这一行为ValidatorOptions.Global.DisplayNameResolver (type, member, expression) { if (member ! null) { return member.Name Foo; } return null; };上面的例子会把所有属性名都加上后缀Foo这只是示意不是真实业务场景但它说明了属性显示名解析的扩展点。DisplayNameResolver属性定义于 ValidatorOptions.cs签名是FuncType, MemberInfo, LambdaExpression, string依次接收容器类型、成员信息与 lambda 表达式。当显示名未显式设置时最终显示名由 PropertyRule.cs 中的GetDisplayName决定优先使用_displayNameFactory即DisplayNameResolver的结果其次使用_displayNameWithName设置的值最后回退到按 PascalCase 拆分的属性名。三、用 OverrideIndexer 定制集合校验的索引格式用RuleForEach校验集合时失败项的属性路径会包含方括号形式的索引例如Foo.BarList[5].Baz。若希望调整这种格式比如去掉方括号、改用元素的自有属性名可以使用OverrideIndexerRuleForEach(x x.BarList) .OverrideIndexer((foo, barList, bar, i) bar.Name)回调签名是FuncT, IEnumerableTCollectionElement, TCollectionElement, int, string四个参数依次为被校验对象、整个集合、当前元素、当前索引。返回值将作为属性链上的索引器文本。上面的例子去掉方括号直接用元素属性名充当索引。源码视角索引器如何进入属性链在 CollectionPropertyRule.cs 的集合遍历中默认行为是indexer index.ToString()且useDefaultIndexFormat true当设置了IndexBuilder即OverrideIndexer注册的回调见 DefaultValidatorOptions.cs时则调用回调并关闭默认格式。随后context.PropertyChain.AddIndexer(indexer, useDefaultIndexFormat)将其拼接到属性链尾部。PropertyChain.cs 的AddIndexer决定拼接格式默认surroundWithBrackets true会生成属性[索引]例如NickNames[0]传false则直接拼接索引文本不带方括号。整个链最终由ToString用ValidatorOptions.Global.PropertyChainSeparator默认.见 ValidatorOptions.cs连接成完整路径。测试 ForEachRuleTests.cs 验证了这一点对NickNames集合{null, foo, null}调用RuleForEach(x x.NickNames) .OverrideIndexer((x, collection, element, index) index ) .NotNull()后失败项的PropertyName分别为NickNames0与NickNames2索引格式完全由回调决定。该测试还有一个异步版本MustAsync说明OverrideIndexer在同步与异步校验路径中行为一致。四、常用定制组合示例以下是一个综合示例将消息覆盖、属性名覆盖与索引覆盖结合使用public class CustomerValidator : AbstractValidatorCustomer { public CustomerValidator() { // 1. 静态消息 占位符 RuleFor(c c.Surname).NotNull().WithMessage(Please ensure you have entered your {PropertyName}); // 2. 引用其他属性的动态消息 RuleFor(c c.Surname).NotNull() .WithMessage(c $Forename is {c.Forename}, please fix the surname); // 3. 仅覆盖消息中的显示名PropertyName 仍是 Surname RuleFor(c c.Surname).NotNull().WithName(Last name); // 4. 完全重命名属性PropertyName 变为 LastName RuleFor(c c.Surname).NotNull().OverridePropertyName(LastName); // 5. 集合校验的索引格式定制 RuleForEach(c c.Orders) .OverrideIndexer((c, orders, order, i) order.OrderNumber) .SetValidator(new OrderValidator()); } }总结WithMessage覆盖单条规则的错误消息支持{PropertyName}、{PropertyValue}、比较类的{ComparisonValue}/{ComparisonProperty}以及 Length 类的{MinLength}/{MaxLength}/{TotalLength}等占位符也可用 lambda 动态求值WithName只替换消息中的显示名不影响ValidationResult中的属性关联OverridePropertyName才真正改写属性名属于高级用法OverrideIndexer通过回调重写集合校验的属性链索引文本其拼接逻辑位于 PropertyChain.AddIndexer属性显示名的全局解析逻辑可通过ValidatorOptions.Global.DisplayNameResolver扩展如需全局替换所有默认消息请参考 localization 而非逐条WithMessage。以上能力对应的完整 API 定义集中在 DefaultValidatorOptions.cs消息格式化核心在 MessageFormatter.cs相关行为均有测试覆盖如 AbstractValidatorTester.cs、ForEachRuleTests.cs可据此进一步深入阅读。赞分享后端【免费下载链接】FluentValidationA popular .NET validation library for building strongly-typed validation rules.项目地址https://gitcode.com/gh_mirrors/fl/FluentValidation点击查看免费下载相关推荐FluentValidation 本地化完全指南默认多语言消息、WithMessage 自定义与 LanguageManager 深度解析FluentValidation 本地化完全指南默认多语言消息、WithMessage 自定义与 LanguageManager 深度解析 导读 本文围绕 F后端FluentValidation自定义错误消息实战WithMessage占位符与本地化国际化完整指南FluentValidation自定义错误消息实战WithMessage占位符与本地化国际化完整指南 FluentValidation 是一款主流的 .NET后端FluentValidation 自定义错误码ErrorCode完全指南从 WithErrorCode 到消息解析原理FluentValidation 自定义错误码ErrorCode完全指南从 WithErrorCode 到消息解析原理 本文面向使用 FluentVali后端上一篇ClickPaste终极指南如何绕过Windows粘贴限制轻松实现跨应用文本输入下一篇3步快速配置Windows安装程序本地化完整指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
企业数字化 ERP 产品动态
相关推荐
Unity 是怎么保证 C# 和 C++ 类型不写错的 一、先把问题讲清楚
Unity 有两半
你写的部分 → C# (游戏逻辑、Update、MonoBehaviour)
引擎自己的部分 → C++ (渲染、物理、动画)你写这一行:
transform.position = new Vector3(1, 2, 3);"移动一个物体"的真正代码是 C++ 写的。所以 C# 必须能调… · 2026/9/24 13:56:09
10分钟解决99%的PSLab for ExpEYES实验故障:工程师私藏排错指南 10分钟解决99%的PSLab for ExpEYES实验故障:工程师私藏排错指南 【免费下载链接】pslab-expeyes PSLab for ExpEYES - Science Experiments and Data Acquisition for Physics Education https://pslab.io 项目地址: https://gitcode.com/gh_mirrors/ps/pslab-exp… · 2026/9/24 13:56:09
国家中小学智慧教育平台电子课本批量下载教程:3步解析出PDF的完整指南 国家中小学智慧教育平台电子课本批量下载教程:3步解析出PDF的完整指南 【免费下载链接】tchMaterial-parser 国家中小学智慧教育平台 电子课本下载工具,帮助您从智慧教育平台中获取电子课本的 PDF 文件网址并进行下载,让您更方便地获取课本内… · 2026/9/24 13:56:09
大麦自动抢票指南:Python Selenium + Appium 双端抢票脚本完整教程 大麦自动抢票指南:Python Selenium Appium 双端抢票脚本完整教程 【免费下载链接】ticket-purchase 大麦自动抢票,支持人员、城市、日期场次、价格选择 项目地址: https://gitcode.com/GitHub_Trending/ti/ticket-purchase
ticket-purchase 是一… · 2026/9/24 17:02:56
ParlAI Seq2Seq Agent 深度指南:基于 RNN 的序列到序列生成模型 NLP人工智能深度学习 【免费下载链接】ParlAI A framework for training and evaluating AI models on a variety of openly available dialogue datasets. 项目地址: https://gitcode.com/gh_mirrors/pa/ParlAI 点击查看 免费下载 本指南围绕 ParlAI 仓库中 parla… · 2026/9/24 17:02:56
Yii 2 错误处理完全指南:ErrorHandler 组件、异常页面定制与多格式错误响应 Yii 2 错误处理完全指南:ErrorHandler 组件、异常页面定制与多格式错误响应 【免费下载链接】yii2 Yii 2: The Fast, Secure and Professional PHP Framework 项目地址: https://gitcode.com/gh_mirrors/yi/yii2
本篇技术指南以 Yii 2 内置的 yii\web\ErrorH… · 2026/9/24 17:02:56
前端实战:滚动监听实现顶部 logo 平滑显隐效果 开发弹窗、侧边抽屉、全屏遮罩这类组件时,经常会遇到一个问题:弹窗弹出后,底层页面依然可以滚动,体验很差。常见方案就是控制 body 的滚动,本文使用 jQuery 实现禁止页面滑动和恢复页面滑动,同时说明坑点。… · 2026/9/24 17:02:56
Visdom 窗口系统完全指南:Window ID、拖拽布局、程序化操作与实时参数编辑 Visdom 窗口系统完全指南:Window ID、拖拽布局、程序化操作与实时参数编辑 【免费下载链接】visdom Tool for real-time visualization, monitoring and collaborative analysis of AI/ML experiments and live data. Supports Python, PyTorch/Torch, NumPy, Tenso… · 2026/9/24 17:02:56
云手机哪个好用?系统兼容性、保活、网络维度分析,怎么选 云手机本质是部署在云端服务器上的 Android 虚拟设备,可实现本地设备关机后云端应用持续运行。本文从技术指标出发,整理了云手机的核心评估维度,对比市面主流几款产品的特性、优缺点,面向个人开发者、测试人员、应用托管用户提供选… · 2026/9/24 17:02:50
基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程 简介:这是一套面向计算机、人工智能、自动化等专业学生与教师的毕业设计级项目资源,围绕YOLOv8实现渔船作业监控系统,可用于毕设、课程设计、大作业或项目立项演示。压缩包共97个文件,约24.21MB,以70个Python源码文件为… · 2026/9/24 0:00:13
1D-CNN时间序列建模实战:从Conv1d原理到工业落地 简介:面向时间序列数据建模的一维卷积神经网络完整实现,适合深度学习入门者及需要快速验证时序模型的研究者,能够从音频、文本、传感器或股价等序列中挖掘局部特征与时间依赖。压缩包体积很小,只有3KB,内含3个Python脚… · 2026/9/24 0:00:26
柔软的L:汉语语流中被忽视的舌肌张力控制 1. 这个“L”不是字母表里的L,而是舌尖上的L最近在几个方言群和语音教学社群里,反复看到有人发一句:“也说字母L:柔软的长舌”。初看以为是英语发音课笔记,点开才发现全是方言爱好者、播音系学生、语言康复师甚至戏曲演… · 2026/9/24 0:00:44