公司动态
验证器藏在哪里?深入解析 Blazored.FluentValidation 的 DI 注册与程序集扫描机制
验证器藏在哪里深入解析 Blazored.FluentValidation 的 DI 注册与程序集扫描机制【免费下载链接】FluentValidationA library for using FluentValidation with Blazor项目地址: https://gitcode.com/gh_mirrors/flue/FluentValidationBlazored.FluentValidation是一个让 FluentValidation 在 Blazor 项目中无缝工作的开源库很多新手第一次用它时都会产生同一个困惑明明写了AbstractValidatorT为什么表单提交时验证规则没有生效答案往往就藏在验证器是怎么被找到的这个环节里。本文就带你把DI 注册与程序集扫描这两条查找路径彻底摸清从此再也不怕验证器迷路。为什么验证器会找不到在 Blazor 的EditForm中验证动作是由FluentValidationValidator /组件驱动的。这个组件本身并不知道你的PersonValidator存在它只负责一件事根据当前表单绑定的模型类型去找对应的验证器。查找规则只有两条按顺序执行先去DI 容器里找有没有注册IValidatorPerson找不到再启动程序集扫描用反射在整个应用的程序集中翻找。这两条路径都藏在库的扩展方法里入口就在 EditContextFluentValidationExtensions.cs 的GetValidatorForModel方法中它是整个查找机制的心脏。第一条路径DI 注册优先命中即用 ✅先看最简单、也最推荐的方式。在Program.cs里把验证器注册进 DI 容器例如示例项目 BlazorServer/Program.cs 中的写法builder.Services.AddTransientIValidatorPerson, PersonValidator(); builder.Services.AddTransientIValidatorAddress, AddressValidator();运行时库会动态构造IValidatorPerson这个泛型类型然后调用serviceProvider.GetService(...)查询容器。如果拿到了实例就直接使用完全不会触发程序集扫描。 小技巧只要走 DI 这条路你的验证器可以随意命名、可以依赖构造函数注入其他服务比如访问数据库做唯一性校验非常灵活。第二条路径程序集扫描自动兜底 ️如果 DI 里没找到库会启动程序集扫描兜底遍历AppDomain.CurrentDomain.GetAssemblies()返回的所有程序集用 FluentValidation 自带的AssemblyScanner.FindValidatorsInAssembly找出里面所有验证器再与当前模型类型匹配。这部分代码有几个值得注意的细节结果被缓存在静态字段AssemblyScanResults中扫描过的程序集也记录在ScannedAssembly列表里不会重复扫描避免性能损耗扫描某个程序集抛异常会被静默吞掉源码注释明确说明这是为了防止第三方依赖的问题搞崩整个应用找到验证器类型后通过ActivatorUtilities.CreateInstance(serviceProvider, modelValidatorType)实例化依然能让验证器享受依赖注入的能力。这个机制正是 BlazorWebAssembly 示例 使用的方案——它的Program.cs里没有注册任何验证器全靠扫描自动发现。DisableAssemblyScanning一键切换查找模式的开关 ️程序集扫描虽方便但反射遍历 全程序集匹配毕竟有开销。库提供了一个DisableAssemblyScanning参数让你明确告诉它只用 DI别扫描FluentValidationValidator DisableAssemblyScanningtrue /这个开关的行为在单元测试里有非常直观的验证见 AssemblyScanning/Tests.cs场景DisableAssemblyScanningDI 注册验证器结果关闭扫描无 DI 注册true❌校验不执行关闭扫描但有 DI 注册true✅校验正常执行开启扫描默认false❌靠扫描自动发现不设置默认值未设置❌靠扫描自动发现从测试可以看出即使关闭了扫描只要 DI 里注册了验证器一切依然正常——DI 永远是第一优先级。程序集扫描的四个注意事项 ⚠️想靠自动扫描找到你的验证器必须满足以下条件验证器类必须是 public 公开类且直接继承自AbstractValidatorT模型的属性类型要和验证器的泛型参数完全匹配扫描结果通过IValidator泛型接口判断归属程序集必须在当前AppDomain可加载的范围内未被引用的程序集自然扫不到部分依赖注入如 Blazor WASM中程序集加载时机不同扫描可能不如服务端可靠——这也是为什么 README 里两个示例采用了不同策略。组件本身的注册与初始化逻辑见 FluentValidationsValidator.cs它在OnInitialized时把自己挂到EditContext上把DisableAssemblyScanning、Validator等参数一并传下去随后的每次表单验证、字段级验证都会走同一条查找链路。实战建议何时用 DI何时靠扫描给普通用户一个简单粗暴的结论项目小、验证器少→ 直接 DI 注册明确、快速、可调试验证器成百上千、不想逐个注册→ 打开程序集扫描DisableAssemblyScanning保持默认false即可想两者兼顾→ 保持默认DI 优先命中扫描作为兜底互不冲突。现在你知道了验证器藏在哪里它要么在 DI 容器里等你注册要么藏在某个程序集的角落等着被扫描。理解这两条路径后遇到验证不生效的问题第一步就该检查——验证器到底走的是哪条路路通了吗 想亲手验证这套机制可以克隆示例项目https://gitcode.com/gh_mirrors/flue/FluentValidation到本地对照 BlazorServer 与 BlazorWebAssembly 两个示例分别运行直观感受两种查找模式的差异。【免费下载链接】FluentValidationA library for using FluentValidation with Blazor项目地址: https://gitcode.com/gh_mirrors/flue/FluentValidation创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考