跳至页脚内容
Iron Academy Logo
C# 工具与生产力

C# 中的 Fluent Validation - 功能强大而简单的数据验证工具

Tim Corey
43分58秒

数据验证是可靠软件开发的支柱之一,在现代 .NET 应用程序中,您需要一种稳健、可维护和可扩展的方式来处理数据验证。 这就是 FluentValidation 的作用所在,它是一个流行的 .NET 库,用于构建强类型验证规则。

在他的深度视频教程"Fluent Validation in C# - The Powerful Yet Easy Data Validation Tool"中,Tim Corey 将带领观众一步步了解 FluentValidation 的使用过程。在本文中,我们将按照 Tim 的讲解,总结要点和代码示例,同时整合相关概念,如自定义验证器、连锁验证器、ASP.NET 集成以及对旧版运行时(如 .NET Core 3.1 和 .NET Standard 2.0)的支持。

简介:为什么选择 FluentValidation?

Tim 在视频开头解释了数据验证如何经常变得重复和混乱。 例如,在项目的不同部分复制和粘贴类似的验证规则就违反了 DRY(不要重复自己)原则。 因此,他介绍了 FluentValidation--一个免费、功能强大的 .NET 验证库,甚至可以在您不拥有的模型上运行,因此非常适合商业项目。

Tim 强调了学以致用的重要性,并指出观众可以通过他的每周挑战系列来培养技能。

演示应用程序概述

Tim 使用了一个 WinForms 演示应用程序,用户可以在其中输入

  • 姓名

  • 姓氏

  • 账户余额

  • 出生日期

虽然这是一个用户界面演示,但验证原则同样适用于 ASP.NET Core、API 测试,甚至控制台应用程序。

信任用户输入的危险

在这一点上,蒂姆提醒开发人员:"永远不要相信用户"。输入往往是不可预测的,例如输入 "ten "表示年龄,而不是 10。在将输入内容保存到数据库之前,必须对其进行验证。

他概述了验证规则示例:

  • 名字和姓氏不能为空。

  • 账户余额应遵循财务规则,如财务赞助的最低要求。

  • 出生日期不能是未来的或超过 120 岁。

验证逻辑应置于何处?

Tim 探讨了配置验证器的选项:

  • 用户界面表单内部

  • 在模型类中使用数据注释

  • 在使用 FluentValidation 的单独验证类中

他指出,数据注释是有限的,在使用外部库或需要更多自定义验证逻辑时往往不适用。

安装 FluentValidation

Tim 使用 Visual Studio,通过 NuGet 将 FluentValidation 添加到他的项目中。 他安装的是 8.1.0 版本,但指出 FluentValidation 是跨平台的,与以下版本兼容:

  • .NET Standard 2.0

  • .NET Core

  • ASP.NET

  • WPF

  • Xamarin

  • 更多内容

Tim 的设置也适用于那些需要支持旧版运行时的人,包括支持 .NET Core 3.1 及更早版本的 FluentValidation 11。

创建验证器类

Tim 演示通过创建一个新类来构建强类型验证规则:

public class PersonValidator : AbstractValidator<Person>
public class PersonValidator : AbstractValidator<Person>

该类包含人员模型的所有验证逻辑。 使用流畅接口,在构造函数中定义验证规则。

第一条验证规则:名字

Tim 使用 lambda 表达式编写了一条规则:

RuleFor(p => p.FirstName).NotEmpty();
RuleFor(p => p.FirstName).NotEmpty();

他使用一个 var 验证器来验证 Person 对象:

var validator = new PersonValidator();
ValidationResult results = validator.Validate(person);
var validator = new PersonValidator();
ValidationResult results = validator.Validate(person);

然后,他循环检查所有验证失败,在列表框中显示用户友好的信息。

字符串长度和自定义消息

Tim 扩展了验证规则:

RuleFor(p => p.FirstName)
    .NotEmpty().WithMessage("First name is empty")
    .Length(2, 50).WithMessage("Length of first name is invalid");
RuleFor(p => p.FirstName)
    .NotEmpty().WithMessage("First name is empty")
    .Length(2, 50).WithMessage("Length of first name is invalid");

使用链式验证器,该规则可确保名称既不会是空的,也不会太短/太长。 Tim 介绍了 Cascade(CascadeMode.Stop),用于在第一次验证失败时停止验证。

自定义验证:名称中的有效字符

Tim 使用一个名为.NET 的方法实现了一个自定义验证器:

private bool BeAValidName(string name)
private bool BeAValidName(string name)

因此,在翻译过程中,我们采用了 "Unicode "技术,将空格和破折号去掉,并确保字符串只包含 Unicode 字母,从而支持国际字符。

自定义规则是这样应用的

.Must(BeAValidName).WithMessage("{PropertyName} contains invalid characters");
.Must(BeAValidName).WithMessage("{PropertyName} contains invalid characters");

这种方法结构非常适合适应其他字段,例如自定义邮政编码验证逻辑功能:

private bool BeAValidPostcode(string postcode)
{
    // Add custom logic here to specify a valid postcode format
}
private bool BeAValidPostcode(string postcode)
{
    // Add custom logic here to specify a valid postcode format
}

然后,您可以将其用于类似的验证器中:

RuleFor(c => c.Postcode).Must(BeAValidPostcode)
    .WithMessage("Please specify a valid postcode");
RuleFor(c => c.Postcode).Must(BeAValidPostcode)
    .WithMessage("Please specify a valid postcode");

这在需要公共类 CustomerValidator 或其他特定领域验证器的商业项目中很常见。

在错误消息中使用内置变量

Tim 演示了如何使用占位符动态增强信息,如

  • {PropertyName}

  • {总长度}

  • {最小长度}和 {最大长度}

这就导致了上下文错误信息,如

"Length of First Name is invalid (was 105)"
"Length of First Name is invalid (was 105)"

这将使用户更容易纠正输入错误。

姓氏和本地化

Tim 将 FirstName 的验证逻辑复制到 LastName,这要归功于 {PropertyName} 的可重用格式化。 他还提到了 WithLocalizedMessage() 用于 ASP.NET需要多语言支持的全球应用程序

重要:CascadeMode 是特定于规则的

Tim 澄清说,CascadeMode.Stop 适用于单个规则,而不是整个模型的全局规则。 如果 FirstName 和 LastName 都为空,即使设置了 CascadeMode,也会触发这两条规则。

出生日期验证

接下来,Tim 添加了一条规则,以确保 出生日期符合实际情况:

private bool BeAValidAge(DateTime dob)
{
    var currentYear = DateTime.Now.Year;
    var dobYear = dob.Year;
    return dobYear <= currentYear && dobYear > (currentYear - 120);
}
private bool BeAValidAge(DateTime dob)
{
    var currentYear = DateTime.Now.Year;
    var dobYear = dob.Year;
    return dobYear <= currentYear && dobYear > (currentYear - 120);
}

像这样使用:

RuleFor(p => p.DateOfBirth)
    .Must(BeAValidAge)
    .WithMessage("Invalid {PropertyName}");
RuleFor(p => p.DateOfBirth)
    .Must(BeAValidAge)
    .WithMessage("Invalid {PropertyName}");

对于验证日期或到期窗口等时间数据,这是一种很好的模式。

最终想法和建议

最后,Tim 总结了 FluentValidation 的主要优势:

  • 集中验证逻辑

  • 易于创建自定义验证器

  • 与 .NET 5 及更新和更旧的运行时兼容

  • 支持复杂模型、列表和异步规则

  • 业余爱好者和商业项目的理想选择

他鼓励观众探索FluentValidation文档中的高级用法,包括嵌套规则、电子邮件属性验证等。

结论

FluentValidation 使 .NET 开发人员能够构建可重用、具有表现力和可维护性的强类型验证规则。 无论您是使用 .NET Core、.NET 8 进行开发,还是在 .NET Core 3.1 上维护传统系统,该库都能让数据验证变得轻而易举。

具有以下功能

  • 用于构建规则的流畅界面

  • 支持自定义邮编验证逻辑

  • 与 Visual Studio 轻松集成

  • 与 API 测试、WinForms 和 ASP.NET 兼容

  • 稳健处理验证失败

FluentValidation 是您 .NET 工具包中的必备工具。 欲了解更多详情,请观看完整的 视频,并订阅 Tim 的 频道,了解更多关于 C# 的精辟视频。

提示:如果您是使用 FluentValidation 的新手,请尝试为公共字符串 Name、字符串 Postcode 等属性实施自己的 CustomerValidator 规则。 使用模拟 API 或 UI 表单进行测试,以获得实践经验。

Hero Worlddot related to C# 中的 Fluent Validation - 功能强大而简单的数据验证工具
Hero Affiliate related to C# 中的 Fluent Validation - 功能强大而简单的数据验证工具

分享您的所爱,赚取更多收入

您为使用 .NET、C#、Java、Python 或 Node.js 的开发人员创建内容吗?将您的专业知识转化为额外收入!

钢铁支援团队

我们每周 5 天,每天 24 小时在线。
聊天
电子邮件
打电话给我