8.Ⅰ 基础使用
📝 模块更新日志
- 新特性
- 突破性变化
- 数据验证比较验证器抽象基类 4.9.8.40 ⏱️2026.04.14 4870e71
- 数据验证服务名称:
AddValidationCore->AddCordon4.9.8.35 ⏱️2026.04.08 9dcdf56 - 数据验证
DecimalPlaces验证器为Decimal(包含验证特性和链式验证) 4.9.8.35 ⏱️2026.04.08 9dcdf56 - 数据验证模块
UseMode方法名称为UseRuleMode4.9.8.25 ⏱️2026.03.23 f50b3d4 - 数据验证模块
CompositeMode枚举名称为RuleMode4.9.8.25 ⏱️2026.03.23 f50b3d4 - 数据验证
ColorValue验证器为Color4.9.8.10 ⏱️2026.01.31 ab9ad35
- 问题修复
- 其他更改
以下内容仅适用于 Furion 4.9.8+ 版本,且不支持 .NET8 以下版本。
8.1 数据验证概述
数据验证是指在程序运行过程中,对输入或传输的数据进行合法性与完整性检查,以确保其符合业务规则和系统预期,防止无效、恶意或格式错误的数据进入核心逻辑,保障应用的稳定性与安全性。
8.1.1 应用场景
数据验证在现代应用开发中具有广泛的应用场景,主要包括:
Web API请求校验:自动验证客户端提交的JSON或表单数据,拦截非法输入。- 用户注册与登录校验:验证邮箱、手机号、密码强度等字段的合法性。
- 表单提交验证:前后端统一校验逻辑,提升体验与数据一致性。
- 领域模型状态校验:确保业务对象在变更或持久化前符合规则。
- 微服务数据契约校验:在服务边界验证输入输出,增强系统健壮性。
- 批量数据导入校验:对
Excel、CSV等批量数据逐条验证并汇总错误。 - 配置参数校验:验证应用配置项的有效性与完整性。
- 多语言错误提示:按用户语言返回本地化验证错误信息。
- 动态规则校验:通过特性或配置灵活启停验证逻辑。
- 异步唯一性校验:如检查用户名或订单号是否已存在。
- 其他场景:适用于多种其他需要保障数据合法性的业务场景。
通过数据验证,开发者能够有效拦截非法输入、统一校验逻辑、降低系统风险,显著提升开发效率与应用的可维护性。
8.2 快速入门
Furion 框架已内置该功能,无需额外安装 NuGet 包。若使用非 Furion 框架,可通过以下命令安装 Cordon 或 Cordon.AspNetCore 包:
- 适用于任何
.NET/C#应用:
dotnet add package Cordon
- 适用于
Web应用(包含Cordon且提供规则集功能):
dotnet add package Cordon.AspNetCore
8.2.1 传统验证方式
在软件开发的早期阶段,尤其是在 Web API 和自动化验证机制尚未普及的年代,开发者通常将数据校验逻辑直接写在业务方法的入口处。这种方式看似简单直接,却容易导致校验逻辑与业务逻辑混杂,带来长期维护问题。
以一个用户注册场景为例,常见代码可能如下:
[HttpPost]
public async Task<bool> Register(User user)
{
// 手动校验参数
if (string.IsNullOrWhiteSpace(user.Name))
throw new ArgumentException("姓名不能为空");
if (user.Name.Length < 2)
throw new ArgumentException("姓名不能少于 2 个字符");
if (user.Age < 18)
throw new ArgumentException("年龄不能小于 18 岁");
if (string.IsNullOrWhiteSpace(user.Password))
throw new ArgumentException("密码不能为空");
if (user.Password != user.ConfirmPassword)
throw new ArgumentException("两次输入的密码不一致");
// 执行实际业务
await _repository.InsertAsync(user);
// ...
return true;
}
在小型或原型项目中,这种写法或许勉强可行。但随着模型复杂度增加,问题迅速显现:
- 职责混杂:校验逻辑嵌入业务方法,违反了单一职责原则;
- 重复代码:若多个方法需要校验
User,相同的判断逻辑会被到处复制; - 维护困难:校验规则分散在各处,修改或扩展时极易遗漏,形成“逻辑碎片”。
久而久之,业务方法不仅变得冗长难读,还难以测试和演进。因此,将校验逻辑硬编码在业务方法中是一种应避免的做法。它污染了核心业务流程,阻碍了验证规则的集中管理和复用,显著增加系统维护成本。
为解决上述问题,更合理的做法是将验证规则与模型本身绑定,使校验逻辑内聚于数据结构,而非散落在业务代码中。
8.2.2 基于特性的验证
与 8.2.1 中将校验逻辑硬编码在业务方法中的做法不同,更合理的方式是将验证规则直接绑定到模型本身。在 .NET 生态中,最常见且标准化的实现手段是使用验证特性——即继承自 ValidationAttribute 的特性类。
通过在模型属性上标注这些特性,支持在不侵入业务代码的前提下,声明式地定义校验规则。验证逻辑由此与模型结构紧密耦合,而与业务流程彻底解耦。
以同样的用户注册场景为例,使用验证特性后的 User 模型如下:
public class User
{
[Required(ErrorMessage = "姓名不能为空"), MinLength(2, ErrorMessage = "姓名不能少于 2 个字符")]
public string? Name { get; set; }
[Min(18, ErrorMessage = "年龄不能小于 18 岁")]
public int Age { get; set; }
[Required(ErrorMessage = "密码不能为空"), Compare(nameof(ConfirmPassword), ErrorMessage = "两次输入的密码不一致")]
public string? Password { get; set; }
public string? ConfirmPassword { get; set; }
}
此时,业务方法不再需要任何手动校验:
[HttpPost]
public async Task<bool> Register(User user) // 在 MVC/WebAPI 应用中实现参数自动校验
{
// 执行实际业务
await _repository.InsertAsync(user);
// ...
return true;
}
在 ASP.NET 等框架中,当模型作为操作方法参数传入时,验证会自动触发。若规则不满足,请求将在进入业务逻辑前被拦截(通常返回 400 Bad Request),从而避免无效数据污染核心流程。
这种方式有效解决了 8.2.1 中提到的三大问题:
- 职责分离:验证属于模型契约,业务方法只关注“做什么”;
- 消除重复:同一模型在任意入口复用相同规则;
- 集中管理:所有校验逻辑内聚于模型定义,便于维护与演进。
此外,框架在完整支持 .NET 内置验证特性(如 [Required]、[MinLength]、[Compare] 等)的基础上,进一步扩展了大量常用验证特性,并允许开发者通过继承 ValidationAttribute 实现自定义验证逻辑,以满足复杂业务场景的需求。
不过,验证特性本质上是静态的、基于属性的声明机制,其表达能力受限于编译时常量与单属性上下文。当验证逻辑涉及跨属性依赖、动态数据源(如数据库查询)、集合元素校验、规则集场景验证或复杂条件组合时,仅靠特性往往难以表达,甚至需要退回到手动判断。
因此,对于超出特性能力边界的验证需求,开发者需要更灵活的机制。
8.2.3 动态验证(自定义验证)
.NET 内置的验证特性(如 [Required]、[MinLength]、[Compare])适用于大多数静态、编译时确定的场景。但在实际业务中,验证逻辑常常依赖运行时动态数据——例如跨属性依赖、动态数据源(如数据库查询)或调用远程 HTTP 服务。这类动态需求已超出预定义特性的表达能力。
以“限制用户注册邮箱域名仅限 outlook.com、qq.com 或 163.com”为例,开发者通常可通过以下三种方式实现动态验证。
方式一:使用 [CustomValidation] 特性
.NET 提供了 [CustomValidation] 特性,允许将验证逻辑委托给一个符合特定签名的静态方法。该方法需返回 ValidationResult,并接受 object? value 参数,可选地还可包含 ValidationContext 参数。
- 定义静态验证方法
创建一个静态类并添加名为 AllowedEmailDomains 的验证方法。类名可任意指定,例如:
public static class CustomValidators
{
private static readonly string[] _allowedDomains = ["@outlook.com", "@qq.com", "@163.com"];
public static ValidationResult? AllowedEmailDomains(object? value, ValidationContext validationContext)
{
if (value is null)
{
return ValidationResult.Success;
}
if (value is not string email)
{
return new ValidationResult("不是有效的邮箱格式。");
}
if (!_allowedDomains.Any(domain => email.EndsWith(domain, StringComparison.OrdinalIgnoreCase)))
{
return new ValidationResult("仅支持 outlook、qq 和 163 邮箱格式。");
}
return ValidationResult.Success;
}
}
- 在
User类中应用该特性:
public class User
{
// ...
[Required]
[EmailAddress]
[CustomValidation(typeof(CustomValidators), nameof(CustomValidators.AllowedEmailDomains))]
public string? EmailAddress { get; set; }
}
在 ASP.NET 等框架中,当 User 作为控制器参数传入时,模型绑定会自动触发所有关联的验证逻辑,包括通过 [CustomValidation] 注册的自定义验证方法。
方式二:自定义验证特性
通过继承 ValidationAttribute 并重写 IsValid(object?, ValidationContext) 方法,可将验证逻辑封装为可复用的声明式特性。
- 定义
AllowedEmailDomainsAttribute特性:
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter)]
public class AllowedEmailDomainsAttribute : ValidationAttribute
{
private readonly string[] _allowedDomains = ["@outlook.com", "@qq.com", "@163.com"];
/// <inheritdoc />
protected override ValidationResult? IsValid(object? value, ValidationContext validationContext)
{
if (value is null)
{
return ValidationResult.Success;
}
if (value is not string email)
{
return new ValidationResult("不是有效的邮箱格式。");
}
if (!_allowedDomains.Any(domain => email.EndsWith(domain, StringComparison.OrdinalIgnoreCase)))
{
return new ValidationResult("仅支持 outlook、qq 和 163 邮箱格式。");
}
return ValidationResult.Success;
}
}
在 IsValid 方法中,可通过 validationContext.GetService(serviceType) 从依赖注入容器中解析所需服务(例如配置、数据库上下文或 HTTP 客户端),从而实现依赖外部资源的动态验证逻辑。
- 在
User类中应用该特性:
public class User
{
// ...
[Required]
[EmailAddress]
[AllowedEmailDomains] // 应用自定义验证特性
public string? EmailAddress { get; set; }
}
与 [CustomValidation] 一样,该特性也会在模型绑定过程中被自动执行。
方式三:实现 IValidatableObject 接口
当验证逻辑涉及多个属性或需要访问模型的完整内部状态时,可让模型实现 IValidatableObject 接口,将验证逻辑内嵌于类型自身:
public class User : IValidatableObject
{
// ...
[Required]
[EmailAddress]
public string? EmailAddress { get; set; }
private readonly string[] _allowedDomains = ["@outlook.com", "@qq.com", "@163.com"];
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (EmailAddress is not null && !_allowedDomains.Any(domain => EmailAddress.EndsWith(domain, StringComparison.OrdinalIgnoreCase)))
{
yield return new ValidationResult("仅支持 outlook、qq 和 163 邮箱格式。", [nameof(EmailAddress)]);
}
}
}
同样,在模型绑定过程中,框架会自动调用 Validate 方法,并将其返回的验证结果与其他特性(如 [Required]、[EmailAddress])的验证结果合并。
尽管上述方式能表达复杂验证规则,但仍存在明显局限:
- 逻辑冗长:即使是简单的多值匹配,也需完整的条件判断和
yield return; - 缺乏组合能力:难以以“与/或/非”方式灵活组合多个验证条件;
- 可读性下降:规则增多时,
Validate方法易演变为庞杂的条件堆砌; - 类型安全性弱:依赖字符串字面量(如
nameof(EmailAddress))标识成员,易引入错误; - 复用成本高:验证逻辑与特定模型强耦合,难以跨类型复用。
因此,在需要高度灵活、可组合且支持强类型校验的系统中,上述机制仍显不足。开发者需要一种既能保持验证逻辑内聚,又能以声明式、链式语法表达复杂规则的验证机制。
8.2.4 链式验证 ✨
在 8.2.3 节中,支持通过 IValidatableObject 接口将验证逻辑内聚于模型,并支持从依赖注入容器中获取服务。当验证逻辑涉及多个条件组合、跨属性校验或外部依赖时,仅靠 if 判断和手动返回 ValidationResult 会使 Validate 方法变得冗长且难以维护。
为此,框架提供链式验证机制,允许在 IValidatableObject.Validate 方法内部以声明式、强类型的方式构建验证规则。该机制通过扩展 ValidationContext,支持在不离开 Validate 方法的前提下,使用流畅的链式语法表达复杂逻辑。
例如,用户邮箱域名的校验可改写为:
public class User : IValidatableObject
{
// ...
[Required]
[EmailAddress]
public string? EmailAddress { get; set; }
/// <inheritdoc />
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
return validationContext.With<User>()
.RuleFor(u => u.EmailAddress)
.MustAny(["@outlook.com", "@qq.com", "@163.com"], (email, domain) => email.EndsWith(domain, StringComparison.OrdinalIgnoreCase))
.WithMessage("仅支持 outlook、qq 和 163 邮箱格式。")
.ToResults();
}
}
在此示例中:
With<User>()从当前ValidationContext启动针对User的链式验证上下文;RuleFor(u => u.EmailAddress)开始为EmailAddress属性定义验证规则链;MustAny(...)是一个自定义验证规则,它对传入的值与多个候选项(如域名列表)逐一调用指定的匹配逻辑,只要任意一项匹配即视为通过;WithMessage(...)为前一个验证器(此处是MustAny)设置错误信息;ToResults()将规则执行结果转换为IEnumerable<ValidationResult>,以满足IValidatableObject接口要求。
该写法具有以下优势:
- 强类型安全:
u => u.EmailAddress在编译时验证属性存在性与类型; - 逻辑内聚:复杂校验封装于单条链,避免多个
if分支; - 可复用性强:自定义验证逻辑(如
MustAny中的委托)可复用于其他属性或模型; - 易于扩展:支持链式追加
When、PreProcess等条件或预处理操作; - 与特性验证共存:
[Required]和[EmailAddress]仍生效,框架自动合并所有验证结果。
此外,为提升代码可维护性和可复用性,可将匹配逻辑封装为独立的方法:
public class User : IValidatableObject
{
// ...
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
return validationContext.With<User>()
.RuleFor(u => u.EmailAddress)
.MustAny(["@outlook.com", "@qq.com", "@163.com"], CheckEmailAddress)
.WithMessage("仅支持 outlook、qq 和 163 邮箱格式。")
.ToResults();
}
private static bool CheckEmailAddress(string email, string domain)
{
return email.EndsWith(domain, StringComparison.OrdinalIgnoreCase);
}
}
独立验证器类
对于复杂、需复用,或需作用于第三方/不可修改类型(如 DTO、POCO)的验证逻辑,可将其封装在独立于模型的验证器类中:继承 AbstractValidator<T>,在构造函数中声明规则链。此类验证器与模型无强耦合,天然支持多场景复用。
首先,定义验证器类:
public class UserValidator : AbstractValidator<User>
{
public UserValidator()
{
RuleFor(u => u.EmailAddress)
.MustAny(["@outlook.com", "@qq.com", "@163.com"], CheckEmailAddress)
.WithMessage("仅支持 outlook、qq 和 163 邮箱格式。");
}
private static bool CheckEmailAddress(string email, string domain)
{
return email.EndsWith(domain, StringComparison.OrdinalIgnoreCase);
}
}
随后,可在多种场景中使用该验证器:
- 在模型中通过
IValidatableObject集成
public class User : IValidatableObject
{
// ...
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
return validationContext.ValidateWith<UserValidator>();
}
}
- 手动实例化调用
public async Task Add(User user)
{
var userValidator = new UserValidator();
// 执行验证
userValidator.Validate(user);
// 其他业务逻辑
}
- 通过依赖注入在服务中使用
public class UserService
{
private readonly UserValidator _userValidator;
public UserService(UserValidator userValidator)
{
_userValidator = userValidator;
}
public async Task Add(User user)
{
// 执行验证
_userValidator.Validate(user);
// 其他业务逻辑
}
}
- 通过特性绑定到操作方法参数
可使用 [ValidateWith<TValidator>] 特性,将验证器绑定到控制器操作的参数:
[ApiController]
[Route("[controller]/[action]")]
public class UserController
{
[HttpPost]
public Task Create([ValidateWith<UserValidator>] User user)
{
return Task.CompletedTask;
}
}
- 在验证器中注入服务(如本地化资源)
验证器构造函数支持依赖注入,例如注入 IStringLocalizer<T> 实现多语言:
public class UserValidator : AbstractValidator<User>
{
public UserValidator(IStringLocalizer<UserValidator> localizer)
{
RuleFor(u => u.EmailAddress)
.MustAny(["@outlook.com", "@qq.com", "@163.com"], CheckEmailAddress)
.WithMessage(localizer["AllowedEmailDomains_ErrorMessage"]);
}
private static bool CheckEmailAddress(string email, string domain)
{
return email.EndsWith(domain, StringComparison.OrdinalIgnoreCase);
}
}
此类验证器不依赖模型定义,具有高度解耦性:
- 可用于
IValidatableObject的自动验证; - 也可通过依赖注入或手动实例化,在服务层、
API控制器或单元测试中直接调用,对任意User实例执行验证。
这种设计显著提升了验证逻辑的复用性与可测试性。
以上操作需确保验证器已注册到服务容器:
services.AddCordon(builder =>
{
builder.AddValidator(typeof(UserValidator));
// 或扫描程序集自动注册
// builder.AddValidatorsFromAssemblies([assembly1, assembly2, ..]);
});
或在 ASP.NET 应用中:
services.AddControllers()
.AddCordon(builder =>
{
builder.AddValidator(typeof(UserValidator));
// 或扫描程序集自动注册
// builder.AddValidatorsFromAssemblies([assembly1, assembly2, ..]);
});
提供与验证特性对等的链式规则
框架为链式验证提供了与 .NET 内置验证特性(如 [Required]、[EmailAddress])功能对等的强类型方法(例如 .Required()、.EmailAddress()),因此无需依赖验证特性即可完整表达所有验证逻辑。同时,若模型仍保留验证特性,框架会自动合并特性验证与链式规则的执行结果,确保所有约束均被检查。
以下示例展示了如何仅通过链式规则,完整实现 User 模型的所有验证逻辑,无需使用任何验证特性:
public class UserValidator : AbstractValidator<User>
{
public UserValidator()
{
RuleFor(u => u.Name)
.Required().WithMessage("姓名不能为空")
.MinLength(2).WithMessage("姓名不能少于 2 个字符");
RuleFor(u => u.Age)
.Min(18).WithMessage("年龄不能小于 18 岁");
RuleFor(u => u.Password)
.Required().WithMessage("密码不能为空")
.Compare(u => u.ConfirmPassword).WithMessage("两次输入的密码不一致");
RuleFor(u => u.EmailAddress)
.Required()
.EmailAddress()
.MustAny(["@outlook.com", "@qq.com", "@163.com"], CheckEmailAddress)
.WithMessage("仅支持 outlook、qq 和 163 邮箱格式。");
}
private static bool CheckEmailAddress(string email, string domain)
{
return email.EndsWith(domain, StringComparison.OrdinalIgnoreCase);
}
}
对于框架尚未内置或自定义的验证特性,可通过 .WithAttributes(params ValidationAttribute[]) 方法将其融入链式验证,例如:
RuleFor(u => u.EmailAddress)
.WithAttributes(new AllowedEmailDomainsAttribute()); // 支持传入多个特性实例
虽然上述写法按属性分段,更利于阅读和维护,但若偏好紧凑风格,也可连续链式书写:
RuleFor(u => u.Name)
.Required().WithMessage("姓名不能为空")
.MinLength(2).WithMessage("姓名不能少于 2 个字符")
.RuleFor(u => u.Age)
.Min(18).WithMessage("年龄不能小于 18 岁")
.RuleFor(u => u.Password)
.Required().WithMessage("密码不能为空")
.Compare(u => u.ConfirmPassword).WithMessage("两次输入的密码不一致")
.RuleFor(u => u.EmailAddress)
.Required()
.EmailAddress()
.MustAny(["@outlook.com", "@qq.com", "@163.com"], CheckEmailAddress)
.WithMessage("仅支持 outlook、qq 和 163 邮箱格式。");
同样的验证逻辑也可直接在模型的 IValidatableObject.Validate 方法中以链式语法编写,无需引入独立验证器类:
public class User : IValidatableObject
{
// ...
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
return validationContext.With<User>()
.RuleFor(u => u.Name)
.Required().WithMessage("姓名不能为空")
.MinLength(2).WithMessage("姓名不能少于 2 个字符")
.RuleFor(u => u.Age)
.Min(18).WithMessage("年龄不能小于 18 岁")
.RuleFor(u => u.Password)
.Required().WithMessage("密码不能为空")
.Compare(u => u.ConfirmPassword).WithMessage("两次输入的密码不一致")
.RuleFor(u => u.EmailAddress)
.Required()
.EmailAddress()
.MustAny(["@outlook.com", "@qq.com", "@163.com"], CheckEmailAddress)
.WithMessage("仅支持 outlook、qq 和 163 邮箱格式。")
.ToResults();
}
private static bool CheckEmailAddress(string email, string domain)
{
return email.EndsWith(domain, StringComparison.OrdinalIgnoreCase);
}
}
适用场景建议
链式验证尤其适合以下情形:
.NET原生验证特性(如[Required])表达能力不足;- 需为第三方或不可修改的类型(如
DTO、POCO)附加验证逻辑; - 验证规则依赖外部服务(如配置、数据库或
HTTP客户端); - 验证逻辑需在多层架构(如应用层、
API层、测试层)中复用。
通过声明式、强类型的链式语法,链式验证有效减少样板代码,特别适合表达组合式、跨属性或依赖运行时数据的业务规则。
8.2.5 嵌套对象与集合验证
在实际业务中,用户提交的数据通常由多个关联模型组成——例如注册时包含家庭住址、多段工作经历或多个兴趣爱好。这类结构天然涉及 嵌套对象(如 Address)和 集合类型(如 List<WorkExperience> 或 List<string>)的验证。
以如下模型为例:
public class Address
{
public string? City { get; set; }
public string? Street { get; set; }
}
public class WorkExperience
{
public string? Company { get; set; }
public string? Position { get; set; }
public int Years { get; set; }
}
public class User
{
public string? Name { get; set; }
public int Age { get; set; }
public Address? Address { get; set; }
public List<WorkExperience>? WorkExperiences { get; set; }
public List<string>? Hobbies { get; set; }
}
框架通过统一的链式 API 支持对不同结构配置验证规则:
- 普通属性与嵌套对象(如
Name、Age、Address)使用RuleFor(...)定义验证规则链(如.Required()、.MinLength(3))。 - 嵌套对象的内部属性:在
RuleFor(...)后调用.ChildRules(...),可深入配置其子属性的验证规则。 - 集合属性(如
WorkExperiences、Hobbies)使用RuleForCollection(...)定义集合级约束(如.MaxLength(5)),并支持进一步细化元素验证:- 若元素为 引用类型(如
WorkExperience,不包括string),可通过.ChildRules(...)配置其内部属性; - 若需对 任意类型 的元素(包括值类型、字符串或引用类型)逐个应用验证,则使用
.EachRules(...)。
- 若元素为 引用类型(如
对同一集合属性,.ChildRules(...) 与 .EachRules(...) 互斥,不可同时使用。应根据元素类型及验证需求择一配置。
验证规则的组织方式
框架支持以下两种验证规则配置范式:
1. 聚合根集中配置(适用于简单场景)
将全部验证逻辑(包括嵌套对象和集合元素的内部规则)集中定义在顶层模型(如 User)中:
public class User : IValidatableObject
{
public string? Name { get; set; }
public int Age { get; set; }
public Address? Address { get; set; }
public List<WorkExperience>? WorkExperiences { get; set; }
public List<string>? Hobbies { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
return validationContext.With<User>()
.RuleFor(u => u.Name).Required().MinLength(3)
.RuleFor(u => u.Age).Age(true)
.RuleFor(u => u.Address).Required().ChildRules(addr =>
{
addr.RuleFor(a => a.City).Required()
.RuleFor(a => a.Street).Required();
})
.RuleForCollection(u => u.WorkExperiences).MaxLength(5).ChildRules(exp =>
{
exp.RuleFor(e => e.Company).Required()
.RuleFor(e => e.Position).Required()
.RuleFor(e => e.Years).Range(1900, 2026);
})
.RuleForCollection(u => u.Hobbies).EachRules(h => h.Required().MinLength(2))
.ToResults();
}
}
优点:
- 逻辑集中,适合快速原型或一次性验证。
局限性:
- 子模型(如
Address、WorkExperience)无法独立复用其验证规则; - 在其他上下文(如独立
API参数、批量导入)中使用时,内部规则不会自动生效,易引发数据不一致。
若未显式要求 Address、WorkExperiences 或 Hobbies 非空(如未调用 .Required()、.NotNull() 或 .NotEmpty()),则当其值为 null 或空集合时,内部验证规则将被跳过,整体视为验证通过。
2. 模型自治 + 聚合根协调(推荐)
采用 “模型自治” 策略:每个模型负责自身验证逻辑,聚合根仅关注结构层面的约束(如非空性、集合长度),不侵入子对象内部细节。
public class Address : IValidatableObject
{
public string? City { get; set; }
public string? Street { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
return validationContext.With<Address>()
.RuleFor(a => a.City).Required()
.RuleFor(a => a.Street).Required()
.ToResults();
}
}
public class WorkExperience : IValidatableObject
{
public string? Company { get; set; }
public string? Position { get; set; }
public int Years { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
return validationContext.With<WorkExperience>()
.RuleFor(w => w.Company).Required()
.RuleFor(w => w.Position).Required()
.RuleFor(w => w.Years).Range(1900, 2026)
.ToResults();
}
}
public class User : IValidatableObject
{
public string? Name { get; set; }
public int Age { get; set; }
public Address? Address { get; set; }
public List<WorkExperience>? WorkExperiences { get; set; }
public List<string>? Hobbies { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
return validationContext.With<User>()
.RuleFor(u => u.Name).Required().MinLength(3)
.RuleFor(u => u.Age).Age(true)
.RuleFor(u => u.Address).Required()
.RuleForCollection(u => u.WorkExperiences).MaxLength(5)
.RuleForCollection(u => u.Hobbies).EachRules(h => h.Required().MinLength(2))
.ToResults();
}
}
优势:
- 验证契约完整且可复用:无论作为独立对象还是嵌套成员,模型的规则始终生效;
- 职责清晰、低耦合:子模型不依赖聚合根,聚合根不承担内部校验;
- 天然支持多场景复用:如单独校验地址、批量处理履历、跨
API共享模型等。
借助 RuleFor(...)、RuleForCollection(...) 与 .ChildRules(...)、.EachRules(...) 的组合,框架提供了类型安全、链式流畅的 API,可表达任意深度的嵌套对象与集合验证逻辑。
在大多数项目中,应优先采用 “模型自治” 策略。这是构建健壮、可维护、可复用验证体系的核心原则。仅在简单场景或快速原型开发中,可考虑聚合根集中配置。
8.2.6 主动验证与依赖注入
在 ASP.NET 应用中,控制器操作方法通常会自动执行模型验证(基于 ModelState),前提是模型使用了验证特性(如 [Required])或实现了 IValidatableObject 接口。不过,在业务层、领域服务、仓储层等非控制器组件中,并无自动验证机制。此时,必须显式调用验证逻辑以确保数据完整性。
框架为此提供了灵活的主动验证能力,支持依赖注入与非依赖注入两种场景。
方式一:通过依赖注入使用 IValidationService(推荐)
若应用支持依赖注入,可通过 IValidationService 执行验证。
1. 注册服务
在使用前,需在 Program.cs(或 Startup.cs)中注册验证服务:
// 在 Startup.cs 中:
services.AddCordon();
// 在 Program.cs 中:
// builder.Services.AddCordon();
2. 注入验证服务
在服务类中注入 IValidationService:
public class UserService
{
private readonly IValidationService _validationService;
public UserService(IValidationService validationService)
{
_validationService = validationService;
}
}
在 .NET 8 及以上版本中,可使用 主构造函数 简化代码:
public class UserService(IValidationService validationService)
{
// 直接使用 validationService
}
也可在方法参数中按需注入:
public class UserService
{
public Task<string> Create([FromServices] IValidationService validationService, User user)
{
// 验证逻辑
}
}
3. 执行验证
注入后,可通过以下方式执行验证:
// 检查对象是否有效
var isValid = validationService.IsValid(user);
// 获取验证结果(不抛异常)
var validationResults = validationService.GetValidationResults(user);
// 验证失败时抛出 ValidationException
validationService.Validate(user);
4. 多模型验证
当一个操作涉及多个模型时,可一次性验证多个对象:
public class OrderService(IValidationService validationService)
{
public void Process(User user, Order order)
{
// 验证多个对象,任一失败即抛出异常
validationService.Validate([user, order]);
}
}
方式二:在非依赖注入环境中使用
在控制台应用、单元测试或静态上下文中,可采用以下方式:
1. 使用静态工厂获取服务实例
var validationService = Validators.Service();
var isValid = validationService.IsValid(user);
var validationResults = validationService.GetValidationResults(user);
validationService.Validate(user);
2. 手动创建验证服务实例
var validationService = new ValidationService();
// 同上使用
3. 直接使用底层验证器
var validator = Validators.AttributeObject(); // 或 new AttributeObjectValidator()
var isValid = validator.IsValid(user, null);
var validationResults = validator.GetValidationResults(user, null);
validator.Validate(user, null);
4. 使用 .NET 内置 Validator 类
var validationContext = new ValidationContext(user);
var validationResults = new List<ValidationResult>();
// 验证所有属性(包括嵌套对象需传 true)
var isValid = Validator.TryValidateObject(user, validationContext, validationResults, validateAllProperties: true);
// 抛异常版本
Validator.ValidateObject(user, validationContext, validateAllProperties: true);
总结
框架的验证机制具备良好的跨层适应能力:
- 在业务层、领域服务、仓储层等非控制器组件中,推荐通过
IValidationService主动验证,确保模型完整性与业务规则一致性; - 在无依赖注入环境(如控制台程序、测试代码)中,仍可通过静态工厂、手动实例化等方式实现同等验证能力。
由此,验证逻辑可贯穿整个应用架构,不再局限于控制器层,从而保障数据一致性与业务规则的全局统一执行。
8.2.7 单值链式验证
除了对象级验证,许多场景还需要对单值(如字符串、整数、枚举或集合等)进行独立校验。框架不仅内置了丰富的单值验证器,还支持与对象验证一致的链式规则定义方式。
以下是框架提供的几种单值验证方式:
1. 使用专用验证器
框架为常见场景提供了以 Validator 结尾的专用验证器。例如,验证电子邮件地址:
// 待验证的值
var value = "support#furion.net";
// 创建验证器实例
var validator = new EmailAddressValidator();
// 检查值是否有效
var isValid = validator.IsValid(value);
// 获取验证结果(不抛异常)
var validationResults = validator.GetValidationResults(value, "Value");
// 验证失败时抛出 ValidationException
validator.Validate(value, "Value");
其中 "Value" 是该值在验证上下文中的显示名称,用于错误信息标识。
如需自定义错误信息,可通过 .WithMessage() 设置:
var validator = new EmailAddressValidator().WithMessage("这不是一个有效的电子邮箱");
2. 使用 Validators 静态类
为简化实例创建,框架提供 Validators 静态工厂类,可直接获取预配置的验证器:
var validator = Validators.EmailAddress();
var isValid = validator.IsValid(value);
var validationResults = validator.GetValidationResults(value, "Value");
validator.Validate(value, "Value");
同样支持自定义信息:
var validator = Validators.EmailAddress().WithMessage("这不是一个有效的电子邮箱");
所有内置验证器均可通过 Validators 快速初始化,避免手动 new,同时行为与直接实例化完全一致。
3. 链式验证(推荐)
对于需要组合多个规则的场景,推荐使用链式语法。可通过 ValueValidator<T> 构建复合验证逻辑:
var validator = new ValueValidator<string>()
.Required()
.EmailAddress().WithMessage("这不是一个有效的电子邮箱")
.MinLength(10)
.WithName("Value"); // 验证上下文中的显示名称(可选)
var isValid = validator.IsValid(value);
var validationResults = validator.GetValidationResults(value);
validator.Validate(value);
也可通过 Validators 静态工厂进一步简化:
var validator = Validators.Value<string>()
.Required()
.EmailAddress().WithMessage("这不是一个有效的电子邮箱")
.MinLength(10)
.WithName("Value");
链式写法语义清晰、易于扩展,天然支持规则复用与信息定制。
为进一步提升可维护性与复用性,还可将规则封装在独立的值验证器类中:通过继承 AbstractValueValidator<T>,将验证逻辑集中定义于构造函数中。这种方式不仅支持依赖注入和生命周期管理,还能在多个场景(如 API 参数、服务层、测试)中复用同一套验证契约。
public class EmailValidator : AbstractValueValidator<string>
{
public EmailValidator()
{
Rule()
.Required()
.EmailAddress().WithMessage("这不是一个有效的电子邮箱")
.MinLength(10)
.WithName("Value");
}
}
该验证器可通过依赖注入或手动实例化,在服务层、API 控制器或单元测试中直接调用,对任意字符串执行验证。
若需通过依赖注入使用值验证器,请确保将其注册到服务容器:
services.AddCordon(builder =>
{
builder.AddValidator(typeof(EmailValidator));
// 或扫描程序集自动注册
// builder.AddValidatorsFromAssemblies([assembly1, assembly2, ..]);
});
或在 ASP.NET 应用中:
services.AddControllers()
.AddCordon(builder =>
{
builder.AddValidator(typeof(EmailValidator));
// 或扫描程序集自动注册
// builder.AddValidatorsFromAssemblies([assembly1, assembly2, ..]);
});
4. 在控制器参数上使用验证特性
在 ASP.NET 应用中,也可直接在操作方法参数上使用验证特性。框架在 .NET 内置特性的基础上,扩展了更多实用特性:
[ApiController]
[Route("[controller]/[action]")]
public class UserController
{
[HttpPost]
public string GetEmailAddress([Required, EmailAddress] string value)
{
return value;
}
}
自定义错误信息可通过 ErrorMessage 属性设置:
[HttpPost]
public string GetEmailAddress([Required, EmailAddress(ErrorMessage = "这不是一个有效的电子邮箱")] string value)
{
return value;
}
此外,还可使用 [ValidateWith<TValidator>] 将自定义值验证器绑定到参数:
[ApiController]
[Route("[controller]/[action]")]
public class UserController
{
[HttpPost]
public void UpdateName([ValidateWith<NameValidator>] string name)
{
}
}
public class NameValidator : AbstractValueValidator<string>
{
public NameValidator()
{
Rule().Required().MinLength(3);
}
}
当请求参数不符合规则时,框架会自动拦截请求并返回验证错误,实现声明式校验。
通过上述方式,无论是在业务逻辑中显式调用,还是在控制器中声明使用,框架均能以统一、灵活、强类型的方式完成单值验证。
8.2.8 在 ASP.NET 应用中使用
数据验证可与 ASP.NET 应用无缝集成,支持运行时配置验证选项(如规则集)以及验证服务的依赖注入。
要在 ASP.NET 应用中启用上述功能,请完成以下配置:
Furion 框架已内置该功能,无需额外安装 NuGet 包。若您使用 Cordon 独立库,请安装 Cordon.AspNetCore 以替代 Cordon。
在 Startup.cs 或 Program.cs 中注册验证服务:
services.AddControllers()
.AddCordon(); // 或进行更多配置:.AddCordon(builder => {});
1. 在 ASP.NET MVC / Web API 中的应用
在控制器或操作方法上,可通过 [ValidationOptions] 特性指定运行时验证选项(如规则集):
[ApiController]
[Route("[controller]/[action]")]
[ValidationOptions(["*"])] // 控制器级别:应用所有规则集
public class UserController
{
[HttpPost] // 自动继承控制器的规则集配置
public Task Create(User user)
{
return Task.CompletedTask;
}
[HttpPost]
[ValidationOptions(["modify", "set-password"])] // 操作方法级别:覆盖控制器配置
public Task Update(User user)
{
return Task.CompletedTask;
}
}
验证选项将自动传递给主验证器及所有嵌套验证器,确保规则集在整个验证链中生效。
2. 在 ASP.NET Razor Pages 中的应用
Razor Pages 同样支持在页面模型或处理方法上使用 [ValidationOptions]:
[ValidationOptions(["*"])] // 页面模型级别
public class UserModel : PageModel
{
public void OnGet()
{
}
[ValidationOptions(["modify", "set-password"])] // 处理方法级别,覆盖页面模型配置
public void OnPost()
{
}
}
通过这种方式,验证规则可根据具体请求上下文动态应用,实现灵活、精准的控制。
除了运行时验证选项,框架还支持 IValidationService 主动验证服务(详见 8.2.6 节)以及独立验证器的依赖注入。
例如:
- 定义对象验证器:
public class UserValidator : AbstractValidator<User>
{
public UserValidator() // 支持注入其他服务,如 IStringLocalizer<UserValidator>
{
RuleFor(u => u.Name)
.Required().WithMessage("姓名不能为空")
.MinLength(2).WithMessage("姓名不能少于 2 个字符");
}
}
- 注册验证器:
services.AddControllers()
.AddCordon(builder =>
{
builder.AddValidator(typeof(UserValidator));
// 或扫描程序集自动注册
// builder.AddValidatorsFromAssemblies([assembly1, assembly2, ..]);
});
- 通过依赖注入使用:
public class UserService
{
private readonly UserValidator _userValidator;
public UserService(UserValidator userValidator)
{
_userValidator = userValidator;
}
public async Task Add(User user)
{
// 执行验证
_userValidator.Validate(user);
// 其他业务逻辑
}
}
此机制使验证逻辑既可声明式集成于请求管道,也可在业务层中显式调用,全面覆盖各类应用场景。
上述依赖注入机制同样适用于单值验证器,即继承自 AbstractValueValidator<T> 的验证器。
8.2.9 规则集(场景化验证)
在实际业务中,同一模型常需在不同场景下执行不同的验证逻辑。例如:
- 用户注册:需验证用户名、邮箱及新密码与确认密码的一致性;
- 修改密码:仅校验旧密码和新密码的合法性;
- 更新资料:可能同时涉及用户名、邮箱、旧密码和新密码的验证。
为支持这种灵活性,验证框架提供了 规则集(Rule Set) 机制:允许在同一个验证器中按命名分组定义多套验证规则,并在运行时根据业务场景动态启用所需规则集。
定义规则集
通过 RuleSet 方法,可在验证器中声明一个命名规则集。其配置委托内使用标准链式规则(如 RuleFor)定义该场景下的验证逻辑。
方式一:在 IValidatableObject 中定义
public class User : IValidatableObject
{
// ...
/// <inheritdoc />
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
return validationContext.With<User>()
// 默认规则集(通配符 '*')
.RuleFor(u => u.Name).Required().MinLength(3).UserName()
.RuleFor(u => u.EmailAddress).Required().EmailAddress()
// 密码设置规则集
.RuleSet("set-password", v => // 支持配置多个规则集 ["*", "set-password"]
{
v.RuleFor(u => u.Password).Required().StrongPassword().Compare(u => u.ConfirmPassword);
})
// 修改密码规则集
.RuleSet("modify-password", v =>
{
v.RuleFor(u => u.OldPassword).Required().StrongPassword();
})
.ToResults();
}
}
方式二:在独立验证器类中定义
对于复杂逻辑、需复用的验证,或需为不可修改类型(如 DTO、POCO)附加验证,推荐使用独立验证器类:
public class UserValidator : AbstractValidator<User>
{
public UserValidator()
{
// 默认规则集(通配符 '*')
RuleFor(u => u.Name).Required().MinLength(3).UserName();
RuleFor(u => u.EmailAddress).Required().EmailAddress();
// 密码设置规则集
RuleSet("set-password", () => // 支持配置多个规则集 ["*", "set-password"]
{
RuleFor(u => u.Password).Required().StrongPassword().Compare(u => u.ConfirmPassword);
});
// 修改密码规则集
RuleSet("modify-password", () =>
{
RuleFor(u => u.OldPassword).Required().StrongPassword();
});
}
}
规则集组合:验证时可传入多个规则集名称,框架将合并所有匹配规则执行验证。
- 用户注册:
["*", "set-password"] - 修改密码:
["modify-password", "set-password"] - 更新用户资料:
["*", "modify-password", "set-password"]
其中 "*" 是保留名称,代表默认规则集,包含所有未被 RuleSet 显式包裹的规则。
在控制器中指定规则集
在 ASP.NET 应用中,可通过 [ValidationOptions] 特性声明当前操作应激活的规则集:
[ApiController]
[Route("[controller]/[action]")]
public class UserController
{
[HttpPost]
[ValidationOptions(["*", "set-password"])]
public Task Create(User user)
{
return Task.CompletedTask;
}
[HttpPost]
[ValidationOptions(["modify-password", "set-password"])]
public Task UpdatePassword(User user)
{
return Task.CompletedTask;
}
[HttpPost]
[ValidationOptions(["*", "modify-password", "set-password"])]
public Task Update(User user)
{
return Task.CompletedTask;
}
}
单值验证器中的规则集
单值验证器同样支持规则集,只需配合 [ValidateWith<TValidator>] 与 [ValidationOptions] 使用:
public class AccountValidator : AbstractValueValidator<string>
{
public AccountValidator()
{
Rule().Required().EmailAddress();
RuleSet("login", () =>
{
Rule().Required().Composite(u => u.UserName().EmailAddress(), CompositeMode.Any);
});
}
}
[ApiController]
[Route("[controller]/[action]")]
public class AuthController
{
[HttpPost]
[ValidationOptions(["login"])]
public void Login([ValidateWith<AccountValidator>] string account)
{
// 仅应用 "login" 规则集
}
}
也可以直接在 [ValidateWith] 特性中指定规则集:
[ValidateWith<AccountValidator>(RuleSets = ["login"])]
若同时使用了 [ValidationOptions] 和 [ValidateWith] 指定规则集,[ValidateWith] 的规则集优先级更高,将覆盖 [ValidationOptions] 中的设置。
要在 ASP.NET 应用中使用上述功能,请确保完成以下配置:
services.AddControllers()
.AddCordon(); // 或进行更多配置:.AddCordon(builder => {});
设计建议
尽管规则集提供了灵活的场景化验证能力,更推荐的做法是为不同业务操作定义专用的输入模型(如 RegisterUserDto、ChangePasswordDto),以显式表达各操作的数据契约,降低模型间的耦合。
规则集更适合以下场景:
- 多个操作确实共享同一输入模型;
- 验证逻辑高度重叠,且希望通过组合避免重复定义。
对于跨模型、跨业务的通用验证逻辑(如密码强度、手机号格式等),应将其封装为可复用的自定义验证器或扩展方法。相关内容将在后续章节详细说明。
8.2.10 链式验证器继承与组合
文档编写中......
8.2.11 验证错误信息本地化(多语言)
在国际化应用中,验证错误信息应能根据用户的语言环境动态呈现,以提供一致且友好的体验。框架全面支持多语言验证错误信息,既兼容 .NET 原生的 IStringLocalizer<T> 机制,也允许通过自定义资源管理器或外部服务灵活实现本地化策略。
在使用本地化之前,请确保已注册以下服务:
services.AddLocalization(); // 本地化服务
services.AddControllers()
.AddDataAnnotationsLocalization(); // 验证特性本地化服务
框架通过 .AddCordon() 默认启用了本地化支持(已自动注册 AddLocalization() 和 AddDataAnnotationsLocalization()),同时也允许外部自定义覆盖相关配置。
验证特性的本地化方式
对于基于 ValidationAttribute 的内置验证特性(如 [Required]、[EmailAddress])以及自定义验证特性,.NET 提供了多种本地化支持方式:
方式一:使用 ErrorMessage 属性(隐式资源查找)
public class User
{
[Required(ErrorMessage = "姓名不能为空")]
[MinLength(2, ErrorMessage = "姓名不能少于 2 个字符")]
public string? Name { get; set; }
}
当使用 ErrorMessage 时,运行时将自动查找与目标类同目录下的资源文件。例如,假设:
- 程序集(项目)名称:
MyProject.Samples - 类完整命名空间:
MyProject.Samples.Models - 类名:
User
在这种情况下,运行时将查找名为 Models.User.[culture].resx 的资源文件,而不是包含程序集名称的完整路径。实际查找路径示例:
Models.User.zh-Hans.resx
Models.User.resx
若在支持依赖注入的环境中注册了本地化服务并设置了 ResourcesPath:
services.AddLocalization(options =>
{
options.ResourcesPath = "Resources";
});
则会在 Resources 文件夹下查找相应文件:
Resources/Models.User.zh-Hans.resx
Resources/Models.User.resx
若使用 Furion 框架,默认会从 Resources 目录下加载名为 Lang.[culture].resx 的资源文件。
方式二:使用 ErrorMessageResourceType 和 ErrorMessageResourceName
通过 ErrorMessageResourceType 和 ErrorMessageResourceName 显式指定自定义的嵌入资源文件:
public class User
{
[Required(ErrorMessage = "姓名不能为空")]
[MinLength(2, ErrorMessageResourceType = typeof(YourValidationMessages), ErrorMessageResourceName = "MinLengthAttribute_ValidationError")]
public string? Name { get; set; }
}
此时,运行时将从 YourValidationMessages.[culture].resx 中读取键为 MinLengthAttribute_ValidationError 的本地化字符串。
ErrorMessage 与 ErrorMessageResourceType、ErrorMessageResourceName 组合不可同时使用。
方式三:在自定义验证特性中动态获取本地化文本
如 8.2.3 节所示,可在 IsValid 方法中通过 validationContext.GetService<IStringLocalizer<T>>() 获取本地化字符串:
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter)]
public class AllowedEmailDomainsAttribute : ValidationAttribute
{
private readonly string[] _allowedDomains = ["@outlook.com", "@qq.com", "@163.com"];
/// <inheritdoc />
protected override ValidationResult? IsValid(object? value, ValidationContext validationContext)
{
if (value is null)
{
return ValidationResult.Success;
}
// 解析字符串本地化服务
var localizer = validationContext.GetService<IStringLocalizer<User>>();
if (value is not string email)
{
return new ValidationResult(localizer?["不是有效的邮箱格式。"] ?? "不是有效的邮箱格式。");
}
if (!_allowedDomains.Any(domain => email.EndsWith(domain, StringComparison.OrdinalIgnoreCase)))
{
return new ValidationResult(localizer?["仅支持 outlook、qq 和 163 邮箱格式。"] ?? "仅支持 outlook、qq 和 163 邮箱格式。");
}
return ValidationResult.Success;
}
}
为避免 localizer 为 null 时重复编写回退逻辑,框架为 IStringLocalizer 提供了 GetString(name) 扩展方法:
return new ValidationResult(localizer.GetString("不是有效的邮箱格式。"));
return new ValidationResult(localizer.GetString("仅支持 outlook、qq 和 163 邮箱格式。"));
当 localizer 为空时,该方法将直接返回参数字符串。
验证器或链式验证中的本地化方式
在框架提供的验证器或链式验证规则中,同样支持本地化操作。
方式一:在 IValidatableObject 中使用本地化
public class User : IValidatableObject
{
public string? Name { get; set; }
/// <inheritdoc />
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
// 解析字符串本地化服务
var localizer = validationContext.GetService<IStringLocalizer<User>>();
return validationContext.With<User>()
.RuleFor(u => u.Name)
.Required().WithMessage(localizer.GetString("姓名不能为空"))
.MinLength(2).WithMessage(localizer.GetString("姓名不能少于 2 个字符"))
.ToResults();
}
}
GetString(name) 是框架提供的扩展方法,用于避免在 localizer 为 null 时重复编写回退逻辑。
在 ASP.NET 环境中,可直接使用索引器语法,例如:localizer["姓名不能为空"]。
方式二:在独立验证器中使用本地化
在独立验证器中,可通过构造函数直接注入 IStringLocalizer<T> 服务:
public class UserValidator : AbstractValidator<User>
{
public UserValidator(IStringLocalizer<User> localizer)
{
RuleFor(u => u.Name)
.Required().WithMessage(localizer["姓名不能为空"])
.MinLength(2).WithMessage(localizer["姓名不能少于 2 个字符"]);
}
}
以上操作需确保验证器已注册到服务容器:
services.AddCordon(builder =>
{
builder.AddValidator(typeof(UserValidator));
// 或扫描程序集自动注册
// builder.AddValidatorsFromAssemblies([assembly1, assembly2, ..]);
});
或在 ASP.NET 应用中:
services.AddControllers()
.AddCordon(builder =>
{
builder.AddValidator(typeof(UserValidator));
// 或扫描程序集自动注册
// builder.AddValidatorsFromAssemblies([assembly1, assembly2, ..]);
});
方式三:WithMessage 方法支持资源类型
框架在验证器中提供了 WithMessage 的重载方法,可显式指定用于本地化信息的资源类型。
RuleFor(u => u.Name).MinLength(2)
.WithMessage(typeof(YourValidationMessages), "MinLengthAttribute_ValidationError");
这种方式允许您直接引用已定义的资源类型,简化了本地化资源的调用流程。
全局默认验证错误信息的本地化替换
.NET 内置验证特性及框架提供的验证特性默认仅提供英文验证错误信息。为避免在非英文环境中反复设置 ErrorMessage,可通过以下方式统一替换默认验证错误信息:
services.AddCordon(builder => // 在 ASP.NET 应用中可使用:services.AddControllers().AddCordon
{
// 替换 .NET 内置验证特性的默认验证错误信息
builder.ConfigureDataAnnotationValidationMessages(message =>
{
message["RequiredAttribute_ValidationError"] = "字段 {0} 是必填项。";
message["StringLengthAttribute_ValidationError"] = "字段 {0} 必须是字符串,且最大长度为 {1}。";
// 更多可替换项参考:https://github.com/dotnet/dotnet/blob/main/src/runtime/src/libraries/System.ComponentModel.Annotations/src/Resources/Strings.resx
});
// 替换框架提供的验证器/特性的默认验证错误信息
builder.ConfigureValidationMessages(message =>
{
message["AgeValidator_ValidationError"] = "字段 {0} 不是有效的年龄。";
message["BankCardValidator_ValidationError"] = "字段 {0} 不是有效的银行卡号。";
// 更多可替换项参考:https://gitee.com/dotnetchina/Cordon/blob/master/src/Cordon/src/Resources/ValidationMessages.resx
});
});
针对中文场景,框架提供一键启用中文验证错误信息的便捷方法:
services.AddCordon(builder => // 在 ASP.NET 应用中可使用:services.AddControllers().AddCordon
{
// 一键替换 .NET 内置验证特性的默认验证错误信息为中文
builder.UseChineseDataAnnotationMessages();
// 一键替换框架提供的验证器/特性的默认验证错误信息为中文
builder.UseChineseValidationMessages();
});
在非依赖注入环境中,可直接使用 ValidationMessageProvider 和 DataAnnotationMessageProvider 静态类进行配置,请确保在程序启动前完成设置:
// 替换 .NET 内置验证特性的默认验证错误信息
DataAnnotationMessageProvider.AddOverrides(new Dictionary<string, string>
{
{"RequiredAttribute_ValidationError", "字段 {0} 是必填项。"},
{"StringLengthAttribute_ValidationError", "字段 {0} 必须是字符串,且最大长度为 {1}。"},
// 更多可替换项参考:https://github.com/dotnet/dotnet/blob/main/src/runtime/src/libraries/System.ComponentModel.Annotations/src/Resources/Strings.resx
});
// 替换框架提供的验证器/特性的默认验证错误信息
ValidationMessageProvider.AddOverrides(new Dictionary<string, string>
{
{"AgeValidator_ValidationError", "字段 {0} 不是有效的年龄。"},
{"BankCardValidator_ValidationError", "字段 {0} 不是有效的银行卡号。"},
// 更多可替换项参考:https://gitee.com/dotnetchina/Cordon/blob/master/src/Cordon/src/Resources/ValidationMessages.resx
});
针对中文场景,框架同样提供了一键启用中文验证错误信息的静态便捷方法:
// 一键替换 .NET 内置验证特性的默认验证错误信息为中文
DataAnnotationMessageProvider.UseChineseMessages();
// 一键替换框架提供的验证器/特性的默认验证错误信息为中文
ValidationMessageProvider.UseChineseMessages();
8.3 验证器 ValidatorBase
验证器是继承自 ValidatorBase 的类。ValidatorBase 是一个抽象基类,用于封装具体的验证逻辑,作为整个验证体系的最小核心单元——所有数据验证均由验证器完成。框架支持验证器的组合、继承、优先级控制和本地化。
8.3.1 成员概览
ValidatorBase 抽象类包含以下成员:
- 受保护构造函数
new()new(string)new(Func<string>)
- 属性
ErrorMessage:错误信息,string?类型ErrorMessageResourceType:错误信息资源类型,Type?类型ErrorMessageResourceName:错误信息资源名称,string?类型RuleSets:规则集,string?[]?类型
- 受保护属性
ErrorMessageString:错误信息字符串,string类型CustomErrorMessageSet:判断是否设置了自定义错误信息,bool类型
- 方法
IsValid(object?):检查值是否有效,虚方法IsValid(object?, IValidationContext?):检查值是否有效,抽象方法,需由派生类实现GetValidationResults(object?, string, IEnumerable<string>?):获取验证结果列表,虚方法GetValidationResults(object?, IValidationContext?):获取验证结果列表,虚方法Validate(object?, string, IEnumerable<string>?):执行验证,失败时抛出ValidationException,虚方法Validate(object?, IValidationContext?):执行验证,失败时抛出ValidationException,虚方法TryValidate(object?, string, IEnumerable<string>?):尝试执行验证,返回ValidatorResult,虚方法TryValidate(object?, IValidationContext?):尝试执行验证,返回ValidatorResult,虚方法FormatErrorMessage(string?):格式化错误信息,虚方法
- 受保护方法
UseResourceKey(Func<string>):使用指定资源键设置验证错误信息OnPropertyChanged(object?, string?):触发属性变更事件
- 静态方法
GetResourceString(string):获取支持外部覆盖的资源字符串GetResourceString(Type, string):获取资源字符串
- 受保护事件
PropertyChanged:属性变更事件,用于监听ErrorMessage、ErrorMessageResourceType、ErrorMessageResourceName和RuleSets的变更
ValidatorBase 提供了一个抽象方法和多个可重写的虚方法。通常只需实现 IsValid(object?, IValidationContext?) 即可快速构建一个功能完整的验证器,其他方法可根据高级需求选择性重写。
8.3.2 验证操作
使用具体验证器(即继承自 ValidatorBase 的非抽象类型)进行数据验证时,需先创建其实例,再根据需求调用 IsValid、GetValidationResults 或 Validate 方法执行验证。这三个方法均提供多种重载形式,详见上一小节。
1. 初始化验证器实例
框架提供以下两种方式:
- 手动
new创建:var validator = new EmailAddressValidator(); - 使用
Validators静态类(推荐):
Validators是框架提供的便捷静态工厂类,提供与验证器类型同名(省略Validator后缀)的工厂方法,用于创建对应的验证器实例:var validator = Validators.EmailAddress();
2. 执行验证
验证器提供以下四种验证方法:
(1)IsValid 方法
用于判断目标值是否有效,适用于无需收集错误信息或需手动控制验证流程的场景:
var value = "support#furion.net";
var isValid = validator.IsValid(value); // => false
该方法还提供带 IValidationContext 参数的重载,可用于传递显示名称、规则集等上下文信息:
var validationContext = new ValidationContext<string>(value)
{
DisplayName = "E-mail",
RuleSets = ["*"]
};
var isValid = validator.IsValid(value, validationContext);
若验证器内部需使用依赖注入服务,可在上下文中传入 IServiceProvider:
var validationContext = new ValidationContext<string>(value, serviceProvider, null);
随后在验证器中可通过 validationContext.GetService(serviceType) 解析所需服务。
(2)GetValidationResults 方法
用于获取所有验证失败结果;若验证通过则返回 null,否则返回 List<ValidationResult>:
var validationResults = validator.GetValidationResults(value, "data");
其中 "data" 为字段的显示名称,用于错误信息格式化。
同样支持 IValidationContext 重载:
var validationResults = validator.GetValidationResults(value, validationContext);
(3)Validate 方法
用于立即执行验证,失败时抛出 ValidationException,是业务开发中最常用的方法之一:
validator.Validate(value, "data");
"data" 同样作为显示名称用于错误信息。
也支持 IValidationContext 重载:
validator.Validate(value, validationContext);
(4)TryValidate 方法
尝试执行验证,返回封装结果的 ValidatorResult 对象:
var validatorResult = validator.TryValidate(value, "data");
// 失败时抛出 ValidationException
validatorResult.ThrowIfInvalid();
"data" 同样作为显示名称用于错误信息。
同样支持 IValidationContext 重载:
var validatorResult = validator.TryValidate(value, validationContext);
ValidatorResult 包含以下成员:
- 属性
IsValid:表示验证是否通过,bool类型ValidationResults:验证结果列表,IReadOnlyList<ValidationResult>?类型Instance:验证的对象,object?或T类型
- 方法
ThrowIfInvalid():若验证未通过,抛出ValidationException
以上四种方法均适用于框架内置及用户自定义的所有验证器。
8.3.3 验证上下文
在复杂验证场景中,验证器往往需要额外信息(如字段显示名称、当前生效的规则集、共享上下文数据)或依赖外部服务(如数据库连接、本地化资源等)。为此,框架引入了 IValidationContext 作为统一的验证上下文载体。
IValidationContext 用于在验证过程中向验证器传递运行时上下文信息。该接口继承自 IServiceProvider,从而支持在验证器内部解析依赖注入的服务。其默认实现为 ValidationContext<T>。
ValidationContext<T> 包含以下成员:
- 构造函数
new(T)new(T, IDictionary<object, object?>?)new(T, IServiceProvider?, IDictionary<object, object?>?)new(T, Func<Type, object?>?, IDictionary<object, object?>?)
- 属性
Instance:被验证的对象,T类型DisplayName:显示名称,string类型MemberNames:成员名称列表,IEnumerable<string>?类型RuleSets:生效的规则集,string?[]?类型Items:共享数据,IDictionary<object, object?>类型
- 方法
GetService(Type):解析注册的服务(由IServiceProvider定义)
通过 IValidationContext,验证器既能获取上下文信息,又能访问依赖服务,从而支持灵活、可扩展的验证逻辑。
8.3.4 错误信息
验证器 ValidatorBase 抽象类默认提供通用错误信息:The field {0} is invalid.。派生类可覆盖该默认信息以提供更具体的描述。
若需在外部自定义错误信息,框架支持以下两种方式:
1. 通过错误信息属性设置
// 直接指定错误信息
var validator = new EmailAddressValidator { ErrorMessage = "这不是有效的电子邮箱格式" };
// 或使用错误信息资源
var validator = new EmailAddressValidator
{
ErrorMessageResourceType = typeof(YourValidationMessages),
ErrorMessageResourceName = "EmailAddressValidator_ValidationError"
};
ErrorMessage 与 ErrorMessageResourceType、ErrorMessageResourceName 组合不可同时使用。
2. 使用 .WithMessage() 扩展方法(推荐)
该方法支持链式调用,语义清晰,适用于构建流式验证规则:
// 直接指定错误信息
var validator = new EmailAddressValidator().WithMessage("这不是有效的电子邮箱格式");
// 或使用错误信息资源
var validator = new EmailAddressValidator()
.WithMessage(typeof(YourValidationMessages), "EmailAddressValidator_ValidationError");
.WithMessage() 不仅语法简洁,还能确保验证器实例的不可变性,是首选的错误信息配置方式。
3. 在 Must 验证中使用 Must.WithMessage()
当使用 MustValidator<T> 进行条件验证时,可通过 Must.WithMessage() 在委托内部动态返回带自定义信息的失败结果:
var validator = new MustValidator<int?>(value => value switch
{
< 10 => false,
10 => Must.WithMessage("值不能等于 10"), // 返回 false 并附带自定义信息
_ => true
});
- 当委托返回
false时,验证失败并使用该MustValidator实例当前生效的错误信息——若已通过.WithMessage()配置,则使用自定义信息;否则回退到默认信息。 - 若需在特定条件下动态指定错误信息,可返回
Must.WithMessage(...),此时将忽略原有配置并使用新信息。
同样支持资源文件重载:
Must.WithMessage(typeof(YourValidationMessages), "Custom_Validation_Error");
优先使用 .WithMessage() 构建验证器;仅在 Must 内部逻辑需动态反馈时使用 Must.WithMessage();避免直接设置 ErrorMessage 属性以保持代码一致性与可维护性。
8.4 内置验证器
框架提供了丰富且实用的内置验证器,覆盖绝大多数常见数据校验场景,可有效满足应用开发中的各类验证需求。
所有内置验证器均以 Validator 结尾(例如 EmailAddressValidator、AgeValidator),建议自定义验证器也遵循这一命名规范,以保持一致性与可读性。
8.4.1 Age 年龄验证器
功能描述
用于验证输入值是否为有效年龄,默认允许范围为 0 到 120 岁。
公开属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
IsAdultOnly | bool | false | 是否仅允许成年人(18 岁及以上) |
AllowStringValues | bool | false | 是否允许字符串数值 |
使用示例
var validator = new AgeValidator();
object? value = -1;
var isValid = validator.IsValid(value);
var validationResults = validator.GetValidationResults(value, "data");
validator.Validate(value, "data");
// 高级配置
var validator = new AgeValidator { IsAdultOnly = true, AllowStringValues = true };
var isValid = validator.IsValid(16);
var isValid = validator.IsValid("20");
建议通过 Validators.Age() 工厂方法创建实例,以提升可维护性并支持未来扩展:
var validator = Validators.Age();
var validator = Validators.Age(isAdultOnly: true, allowStringValues: true);
验证错误信息资源
| 资源键 | 默认信息 |
|---|---|
AgeValidator_ValidationError | The field {0} is not a valid age. |
AgeValidator_ValidationError_IsAdultOnly | The field {0} must be at least 18 years old. |
可以通过上述资源键替换验证器的默认错误信息。例如:
services.AddCordon(builder => // 在 ASP.NET 应用中可使用:services.AddControllers().AddCordon
{
builder.ConfigureValidationMessages(message =>
{
message["AgeValidator_ValidationError"] = "字段 {0} 不是有效的年龄。";
message["AgeValidator_ValidationError_IsAdultOnly"] = "字段 {0} 必须年满 18 岁。";
});
});
8.4.2 AllowedValues 允许值验证器
功能描述
用于验证输入值是否包含在预设的允许值列表中。
公开属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
Values | object?[] | 允许的值列表 |
使用示例
var validator = new AllowedValuesValidator(1, "furion", true);
object? value = "百小僧";
var isValid = validator.IsValid(value);
var validationResults = validator.GetValidationResults(value, "data");
validator.Validate(value, "data");
建议通过 Validators.AllowedValues() 工厂方法创建实例,以提升可维护性并支持未来扩展:
var validator = Validators.AllowedValues(1, "furion", true);
验证错误信息资源
| 资源键 | 默认信息 |
|---|---|
AllowedValuesValidator_ValidationError | The {0} field does not equal any of the values specified in AllowedValuesValidator. |
可以通过上述资源键替换验证器的默认错误信息。例如:
services.AddCordon(builder => // 在 ASP.NET 应用中可使用:services.AddControllers().AddCordon
{
builder.ConfigureValidationMessages(message =>
{
message["AllowedValuesValidator_ValidationError"] = "字段 {0} 的值不在 AllowedValuesValidator 指定的允许值列表中。";
});
});
8.4.3 AttributeObject 对象验证特性验证器
功能描述
用于执行基于 .NET 验证特性的对象级验证,包括:
- 属性上标注的验证特性(如
[Required]、[Range]等); - 实现了
IValidatableObject接口的自定义Validate方法。
公开属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
ValidateAllProperties | bool | true | 是否验证所有属性的验证特性。 若设置为 true,则会同时验证所有属性以及 IValidatableObject.Validate 方法;若设置为 false,则仅验证 IValidatableObject.Validate 方法。 |
使用示例
以 User 模型为例:
public class User : IValidatableObject
{
[Range(1, int.MaxValue)]
public int Id { get; set; }
[Required, Length(3, 16)]
public string? Name { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
return [];
}
}
var validator = new AttributeObjectValidator();
var user = new User { Id = 1, Name = null };
var validationContext = new ValidationContext<User>(user);
var isValid = validator.IsValid(user, validationContext);
var validationResults = validator.GetValidationResults(user, validationContext);
validator.Validate(user, validationContext);
// 仅验证 IValidatableObject.Validate
var validator = new AttributeObjectValidator(validateAllProperties: false);
建议通过 Validators.AttributeObject() 工厂方法创建实例,以提升可维护性并支持未来扩展:
var validator = Validators.AttributeObject();
var validator = Validators.AttributeObject(validateAllProperties: false);
验证错误信息资源
该验证器不生成自有错误信息,而是直接复用
.NET内置验证特性(如[Required]、[Range]等)或IValidatableObject.Validate返回的ValidationResult中的信息,因此无需额外配置资源键。
8.4.4 AttributeProperty 属性验证特性验证器
功能描述
用于对指定属性执行基于 .NET 验证特性(如 [Required]、[StringLength] 等)的验证,仅针对单个属性进行校验。
公开属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
Property | PropertyInfo | 要验证的属性 |
使用示例
以 User 模型为例:
public class User
{
[Required, StringLength(16)]
public string? Name { get; set; }
}
var validator = new AttributePropertyValidator<User>(u => u.Name);
var user = new User { Name = null };
var validationContext = new ValidationContext<User>(user);
var isValid = validator.IsValid(user, validationContext);
var validationResults = validator.GetValidationResults(user, validationContext);
validator.Validate(user, validationContext);
建议通过 Validators.AttributeProperty<T>() 工厂方法创建实例,以提升可维护性并支持未来扩展:
var validator = Validators.AttributeProperty<User>(u => u.Name);
验证错误信息资源
该验证器不生成自有错误信息,而是直接使用属性上标注的
.NET验证特性(如[Required]、[StringLength]等)所携带的错误信息,因此无需额外配置资源键。
8.4.5 AttributeValue 单值验证特性验证器
功能描述
用于对单值应用一组 .NET 验证特性(如 [Required]、[StringLength] 等)进行校验,适用于脱离模型上下文的独立值验证场景。
公开属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
Attributes | ValidationAttribute[] | 验证特性列表 |
使用示例
using var validator = new AttributeValueValidator(new RequiredAttribute(), new StringLengthAttribute(16));
string? value = null;
var validationContext = new ValidationContext<string?>(value);
var isValid = validator.IsValid(value, validationContext);
var validationResults = validator.GetValidationResults(value, validationContext);
validator.Validate(value, validationContext);
建议通过 Validators.AttributeValue() 工厂方法创建实例,以提升可维护性并支持未来扩展:
using var validator = Validators.AttributeValue(new RequiredAttribute(), new StringLengthAttribute(16));
为 AttributeValueValidator 设置的错误信息(如 ErrorMessage、ErrorMessageResourceName 和 ErrorMessageResourceType)会自动同步至其内部的单个验证特性实例。
验证错误信息资源
该验证器会直接复用传入的
ValidationAttribute实例中定义的错误信息——包括通过ErrorMessage、ErrorMessageResourceType和ErrorMessageResourceName配置的本地化信息,或自定义验证特性返回的ValidationResult中指定的ErrorMessage。因此,无需额外注册资源键。
8.4.6 BankCard 银行卡号验证器
功能描述
用于验证输入值是否为有效的银行卡号,依据 Luhn 算法 进行校验。
公开属性
无
使用示例
var validator = new BankCardValidator();
object? value = "41111111111111111111";
var isValid = validator.IsValid(value);
var validationResults = validator.GetValidationResults(value, "data");
validator.Validate(value, "data");
建议通过 Validators.BankCard() 工厂方法创建实例,以提升可维护性并支持未来扩展:
var validator = Validators.BankCard();
验证错误信息资源
| 资源键 | 默认信息 |
|---|---|
BankCardValidator_ValidationError | The field {0} is not a valid bank card number. |
可以通过上述资源键替换验证器的默认错误信息。例如:
services.AddCordon(builder => // 在 ASP.NET 应用中可使用:services.AddControllers().AddCordon
{
builder.ConfigureValidationMessages(message =>
{
message["BankCardValidator_ValidationError"] = "字段 {0} 不是有效的银行卡号。";
});
});
8.4.7 Base64String Base64 字符串验证器
功能描述
用于验证输入值是否为符合标准格式的有效 Base64 编码字符串。
公开属性
无
使用示例
var validator = new Base64StringValidator();
object? value = "ZnVdyaW9u";
var isValid = validator.IsValid(value);
var validationResults = validator.GetValidationResults(value, "data");
validator.Validate(value, "data");
建议通过 Validators.Base64String() 工厂方法创建实例,以提升可维护性并支持未来扩展:
var validator = Validators.Base64String();
验证错误信息资源
| 资源键 | 默认信息 |
|---|---|
Base64StringValidator_ValidationError | The {0} field is not a valid Base64 encoding. |
可以通过上述资源键替换验证器的默认错误信息。例如:
services.AddCordon(builder => // 在 ASP.NET 应用中可使用:services.AddControllers().AddCordon
{
builder.ConfigureValidationMessages(message =>
{
message["Base64StringValidator_ValidationError"] = "字段 {0} 不是有效的 Base64 编码。";
});
});
8.4.8 ChineseName 中文姓名验证器
功能描述
用于验证输入值是否为符合常见规范的中文姓名(支持 2–16 个汉字,包含复姓和单字名等常见形式)。
公开属性
无
使用示例
var validator = new ChineseNameValidator();
object? value = "蒙奇·D·路飞";
var isValid = validator.IsValid(value);
var validationResults = validator.GetValidationResults(value, "data");
validator.Validate(value, "data");
建议通过 Validators.ChineseName() 工厂方法创建实例,以提升可维护性并支持未来扩展:
var validator = Validators.ChineseName();
验证错误信息资源
| 资源键 | 默认信息 |
|---|---|
ChineseNameValidator_ValidationError | The field {0} is not a valid Chinese name. |
可以通过上述资源键替换验证器的默认错误信息。例如:
services.AddCordon(builder => // 在 ASP.NET 应用中可使用:services.AddControllers().AddCordon
{
builder.ConfigureValidationMessages(message =>
{
message["ChineseNameValidator_ValidationError"] = "字段 {0} 不是有效的中文姓名。";
});
});
8.4.9 Chinese 中文验证器
功能描述
用于验证输入值是否完全由中文汉字(包括常见简体、繁体汉字)组成。非字符串类型或包含任何非汉字字符(如字母、数字、标点、空格等)均视为无效。
公开属性
无
使用示例
var validator = new ChineseValidator();
object? value = "Furion";
var isValid = validator.IsValid(value);
var validationResults = validator.GetValidationResults(value, "data");
validator.Validate(value, "data");
建议通过 Validators.Chinese() 工厂方法创建实例,以提升可维护性并支持未来扩展:
var validator = Validators.Chinese();
验证错误信息资源
| 资源键 | 默认信息 |
|---|---|
ChineseValidator_ValidationError | The field {0} contains invalid Chinese characters. |
可以通过上述资源键替换验证器的默认错误信息。例如:
services.AddCordon(builder => // 在 ASP.NET 应用中可使用:services.AddControllers().AddCordon
{
builder.ConfigureValidationMessages(message =>
{
message["ChineseValidator_ValidationError"] = "字段 {0} 包含无效的中文字符。";
});
});
8.4.10 Color 颜色验证器
功能描述
用于验证输入值是否为有效的 CSS 颜色。支持多种常见格式,包括十六进制、RGB、RGBA,并可选支持 HSL 和 HSLA。
公开属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
FullMode | bool | false | 是否启用完整模式。在完整模式下,支持的颜色格式包括:十六进制颜色、RGB、RGBA、HSL 和 HSLA;若未启用,则仅支持十六进制颜色、RGB 和 RGBA。 |
使用示例
var validator = new ColorValidator();
object? value = "hsl(0, 100%, 50%)";
var isValid = validator.IsValid(value);
var validationResults = validator.GetValidationResults(value, "data");
validator.Validate(value, "data");
// 高级配置
var validator = new ColorValidator { FullMode = true };
建议通过 Validators.Color() 工厂方法创建实例,以提升可维护性并支持未来扩展:
var validator = Validators.Color();
var validator = Validators.Color(fullMode: true);
验证错误信息资源
| 资源键 | 默认信息 |
|---|---|
ColorValidator_ValidationError | The field {0} is not a valid color. |
可以通过上述资源键替换验证器的默认错误信息。例如:
services.AddCordon(builder => // 在 ASP.NET 应用中可使用:services.AddControllers().AddCordon
{
builder.ConfigureValidationMessages(message =>
{
message["ColorValidator_ValidationError"] = "字段 {0} 不是有效的颜色。";
});
});
8.4.11 Compare 比较两个属性验证器
功能描述
用于验证对象中两个属性的值是否相等。
公开属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
Property | PropertyInfo | 主要比较属性 | |
OtherProperty | PropertyInfo | 被比较的另一属性 |
使用示例
var validator = new CompareValidator<User>(u => u.Password, u => u.ConfirmPassword);
var user = new User { Password = "q1we3", ConfirmPassword = "q1w2e3r4" };
var isValid = validator.IsValid(user);
var validationResults = validator.GetValidationResults(user, "data");
validator.Validate(user, "data");
// 也支持通过属性名指定第二个属性
var validator = new CompareValidator<User>(u => u.Password, "ConfirmPassword");
建议通过 Validators.Compare<T>() 工厂方法创建实例,以提升可维护性并支持未来扩展:
var validator = Validators.Compare<User>(u => u.Password, u => u.ConfirmPassword);
var validator = Validators.Compare<User>(u => u.Password, "ConfirmPassword");
验证错误信息资源
| 资源键 | 默认信息 |
|---|---|
CompareValidator_ValidationError | '{0}' and '{1}' do not match. |
可以通过上述资源键替换验证器的默认错误信息。例如:
services.AddCordon(builder => // 在 ASP.NET 应用中可使用:services.AddControllers().AddCordon
{
builder.ConfigureValidationMessages(message =>
{
message["CompareValidator_ValidationError"] = "“{0}”与“{1}”不匹配。";
});
});
8.4.12 CustomValidation 自定义验证特性验证器
功能描述
通过指定类型和静态方法,实现对属性或类实例的自定义验证逻辑。
公开属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
ValidatorType | Type | 执行自定义验证的类型 | |
Method | string | 验证方法 |
使用示例
以 CustomValidators 静态类为例:
public static class CustomValidators
{
// ValidationContext 参数为可选,按需添加
public static ValidationResult? ValidateValue(object? value, ValidationContext context) =>
value switch
{
null => ValidationResult.Success,
string { Length: < 3 } => new ValidationResult("字符串长度不能小于 3"),
_ => ValidationResult.Success
};
}
与其他验证器不同,CustomValidation 需通过 CustomValidationAttribute 实例初始化,并作为 AttributeValueValidator 的构造参数传入:
using var validator = new AttributeValueValidator(new CustomValidationAttribute(typeof(CustomValidators), nameof(CustomValidators.ValidateValue));
object? value = "fu";
var isValid = validator.IsValid(value);
var validationResults = validator.GetValidationResults(value, "data");
validator.Validate(value, "data");
建议通过 Validators.CustomValidation() 工厂方法创建实例,以提升可维护性并支持未来扩展:
using var validator = Validators.CustomValidation(typeof(CustomValidators), nameof(CustomValidators.ValidateValue);
为 AttributeValueValidator 设置的错误信息(如 ErrorMessage、ErrorMessageResourceName 和 ErrorMessageResourceType)会自动同步至其内部的 CustomValidationAttribute 实例。
- 若验证方法返回非空的
ValidationResult且其ErrorMessage不为空,则使用该信息,并覆盖特性或资源中配置的错误信息。 - 若返回的
ValidationResult的ErrorMessage为null或空字符串(例如new ValidationResult(null)),则使用外部配置的错误信息(如ErrorMessage或本地化资源)。
验证错误信息资源
| 资源键 | 默认信息 |
|---|---|
CustomValidationAttribute_ValidationError | {0} is not valid. |
可以通过上述资源键替换验证器的默认错误信息。例如:
services.AddCordon(builder => // 在 ASP.NET 应用中可使用:services.AddControllers().AddCordon
{
builder.ConfigureDataAnnotationValidationMessages(message =>
{
message["CustomValidationAttribute_ValidationError"] = "{0} 无效。";
});
});
8.4.13 DateOnly 日期验证器
功能描述
用于验证输入值是否可解析为有效的 DateOnly 实例,支持自定义日期格式、区域设置及解析行为控制。
公开属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
Formats | string[] | 允许的日期格式列表(如 yyyy-MM-dd) | |
Provider | IFormatProvider? | CultureInfo.InvariantCulture | 格式提供器 |
Style | DateTimeStyles | DateTimeStyles.None | 日期解析样式,需与 Formats 属性搭配使用 |
使用示例
var validator = new DateOnlyValidator();
object? value = "2023/09/26";
var isValid = validator.IsValid(value);
var validationResults = validator.GetValidationResults(value, "data");
validator.Validate(value, "data");
// 高级配置
var validator = new DateOnlyValidator("yyyy/MM/dd", "yyyy-MM-dd", "dd/MM/yyyy");
建议通过 Validators.DateOnly() 工厂方法创建实例,以提升可维护性并支持未来扩展:
var validator = Validators.DateOnly();
var validator = Validators.DateOnly("yyyy/MM/dd", "yyyy-MM-dd", "dd/MM/yyyy");
验证错误信息资源
| 资源键 | 默认信息 |
|---|---|
DateOnlyValidator_ValidationError | The field {0} must be a valid date. |
DateOnlyValidator_ValidationError_Formats | The field {0} must be a valid date in the following format(s): {1}. |
可以通过上述资源键替换验证器的默认错误信息。例如:
services.AddCordon(builder => // 在 ASP.NET 应用中可使用:services.AddControllers().AddCordon
{
builder.ConfigureValidationMessages(message =>
{
message["DateOnlyValidator_ValidationError"] = "字段 {0} 必须是有效的日期。";
message["DateOnlyValidator_ValidationError_Formats"] = "字段 {0} 必须是符合以下格式之一的有效日期:{1}。";
});
});
8.4.14 DateTime 时刻验证器
功能描述
用于验证输入值是否可解析为有效的 DateTime 实例,支持自定义日期时间格式、区域设置及解析行为控制。
公开属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
Formats | string[] | 允许的日期时间格式列表(如 yyyy-MM-dd HH:mm:ss) | |
Provider | IFormatProvider? | CultureInfo.InvariantCulture | 格式提供器 |
Style | DateTimeStyles | DateTimeStyles.None | 日期时间解析样式,需与 Formats 属性搭配使用 |
使用示例
var validator = new DateTimeValidator();
object? value = "2023/09/26 13:14:15";
var isValid = validator.IsValid(value);
var validationResults = validator.GetValidationResults(value, "data");
validator.Validate(value, "data");
// 高级配置
var validator = new DateTimeValidator("yyyy/MM/dd HH:mm:ss", "yyyy-MM-dd HH:mm:ss", "dd/MM/yyyy HH:mm:ss");
建议通过 Validators.DateTime() 工厂方法创建实例,以提升可维护性并支持未来扩展:
var validator = Validators.DateTime();
var validator = Validators.DateTime("yyyy/MM/dd HH:mm:ss", "yyyy-MM-dd HH:mm:ss", "dd/MM/yyyy HH:mm:ss"));
验证错误信息资源
| 资源键 | 默认信息 |
|---|---|
DateTimeValidator_ValidationError | The field {0} must be a valid datetime. |
DateTimeValidator_ValidationError_Formats | The field {0} must be a valid datetime in the following format(s): {1}. |
可以通过上述资源键替换验证器的默认错误信息。例如:
services.AddCordon(builder => // 在 ASP.NET 应用中可使用:services.AddControllers().AddCordon
{
builder.ConfigureValidationMessages(message =>
{
message["DateTimeValidator_ValidationError"] = "字段 {0} 必须是有效的日期时间。";
message["DateTimeValidator_ValidationError_Formats"] = "字段 {0} 必须是符合以下格式之一的有效日期时间:{1}。";
});
});
8.4.15 DecimalPlaces 小数位数验证器
功能描述
用于验证数值的小数位数是否不超过指定的最大值。
公开属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
MaxDecimalPlaces | int | — | 允许的最大有效小数位数(构造函数传入,不可变) |
AllowStringValues | bool | false | 是否允许字符串数值 |
使用示例
// 基础使用:最多 2 位小数
var validator = new DecimalPlacesValidator(2);
var isValid = validator.IsValid(123.456m); // false(3 位小数)
var validationResults = validator.GetValidationResults(123.456m, "Price"); // 返回错误
validator.Validate(123.456m, "Price"); // 抛出 ValidationException
// 允许字符串输入
var validator = new DecimalPlacesValidator(3) { AllowStringValues = true };
var isValid = validator.IsValid("123.45"); // true(2 位小数)
var isValid = validator.IsValid("123.4567"); // false(4 位小数)
推荐通过 Validators.DecimalPlaces(...) 工厂方法创建实例,便于未来扩展。
验证错误信息资源键
| 资源键 | 默认信息 |
|---|---|
DecimalPlacesValidator_ValidationError | The field {0} must not have more than '{1}' decimal places. |
8.4.16 DeniedValues 禁止值验证器
功能描述
用于验证目标值是否不在指定的禁止值列表中。
公开属性
该验证器通过构造函数传入禁止值列表,无额外公开属性。
使用示例
// 基础使用
var validator = new DeniedValuesValidator("admin", "root", "guest");
var isValid = validator.IsValid("admin"); // false
var validationResults = validator.GetValidationResults("admin", "Username"); // 返回错误
validator.Validate("admin", "Username"); // 抛出 ValidationException
// 支持混合类型值
var validator = new DeniedValuesValidator(0, -1, "", null, "N/A");
var isValid = validator.IsValid(1); // true
var isValid = validator.IsValid(""); // false
推荐通过 Validators.DeniedValues(...) 工厂方法创建实例,便于未来扩展。
验证错误信息资源键
| 资源键 | 默认信息 |
|---|---|
DeniedValuesValidator_ValidationError | The {0} field equals one of the values specified in DeniedValuesValidator. |
8.4.17 Domain 域名验证器
功能描述
用于验证字符串是否为有效的域名(不含协议,如 https:// 或 http://),支持国际化域名(IDN)并遵循 RFC 1034 标准(最大长度 253 字符)。
公开属性
该验证器无额外公开属性。
使用示例
// 基础使用
var validator = new DomainValidator();
var isValid = validator.IsValid("example..com"); // false(连续点)
var validationResults = validator.GetValidationResults("invalid_domain", "Host"); // 返回错误
validator.Validate("_invalid.com", "Host"); // 抛出 ValidationException
// 支持国际化域名和合法格式
var validator = new DomainValidator();
var isValid = validator.IsValid("example.com"); // true
var isValid = validator.IsValid("中国.cn"); // true(自动转 Punycode 验证)
推荐通过 Validators.Domain() 工厂方法创建实例,便于未来扩展。
验证错误信息资源键
| 资源键 | 默认信息 |
|---|---|
DomainValidator_ValidationError | The field {0} is not a valid domain name. |
8.4.18 EmailAddress 邮箱地址验证器
功能描述
用于验证字符串是否为有效的电子邮件地址格式。
公开属性
该验证器无额外公开属性。
使用示例
// 基础使用
var validator = new EmailAddressValidator();
var isValid = validator.IsValid("invalid-email"); // false
var validationResults = validator.GetValidationResults("user@", "Email"); // 返回错误
validator.Validate("user@", "Email"); // 抛出 ValidationException
// 验证有效邮箱
var validator = new EmailAddressValidator();
var isValid = validator.IsValid("user@example.com"); // true
var isValid = validator.IsValid("test.email+tag@domain.co.uk"); // true
推荐通过 Validators.EmailAddress() 工厂方法创建实例,便于未来扩展。
验证错误信息资源键
| 资源键 | 默认信息 |
|---|---|
EmailAddressValidator_ValidationError | The {0} field is not a valid e-mail address. |
8.4.19 Empty 空值验证器
功能描述
用于验证值是否为空(null)或空集合/数组/字符串(长度为 0)。
公开属性
该验证器无额外公开属性。
使用示例
// 基础使用
var validator = new EmptyValidator();
var isValid = validator.IsValid(new List<int>()); // true
var validationResults = validator.GetValidationResults("hello", "Data"); // 返回错误(非空)
validator.Validate("non-empty", "Data"); // 抛出 ValidationException
// 验证各种空值
var validator = new EmptyValidator();
var isValid = validator.IsValid((string?)null); // true
var isValid = validator.IsValid(new int[0]); // true
推荐通过 Validators.Empty() 工厂方法创建实例,便于未来扩展。
验证错误信息资源键
| 资源键 | 默认信息 |
|---|---|
EmptyValidator_ValidationError | The field {0} must be empty. |
8.4.20 EndsWith 结尾字符串验证器
功能描述
用于验证字符串是否以指定的字符或字符串结尾。
公开属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
SearchValue | string | — | 检索的值(通过构造函数传入,不可变) |
Comparison | StringComparison | StringComparison.Ordinal | 字符串比较方式 |
使用示例
// 基础使用
var validator = new EndsWithValidator(".com");
var isValid = validator.IsValid("example.org"); // false
var validationResults = validator.GetValidationResults("test.net", "Domain"); // 返回错误
validator.Validate("invalid.io", "Domain"); // 抛出 ValidationException
// 自定义比较方式
var validator = new EndsWithValidator("TXT") { Comparison = StringComparison.OrdinalIgnoreCase };
var isValid = validator.IsValid("report.txt"); // true
var isValid = validator.IsValid("data.TXT"); // true
推荐通过 Validators.EndsWith(...) 工厂方法创建实例,便于未来扩展。
验证错误信息资源键
| 资源键 | 默认信息 |
|---|---|
EndsWithValidator_ValidationError | The field {0} does not end with the string '{1}'.'. |
8.4.21 Enum 枚举验证器
功能描述
用于验证值是否为指定枚举类型的已定义成员。支持普通枚举和 [Flags] 枚举模式。
公开属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
EnumType | Type | — | 枚举类型(通过构造函数传入,不可变) |
SupportFlags | bool | false | 是否支持 Flags 模式 |
使用示例
// 基础使用:验证普通枚举
var validator = new EnumValidator(typeof(Status));
var isValid = validator.IsValid("Invalid"); // false
var validationResults = validator.GetValidationResults("Pending", "Status"); // true → 无错误
validator.Validate("Unknown", "Status"); // 抛出 ValidationException
// 启用 Flags 支持
var validator = new EnumValidator(typeof(FileAccess)) { SupportFlags = true };
var isValid = validator.IsValid("Read,Write"); // true(若 FileAccess 有 [Flags])
var isValid = validator.IsValid(3); // true(组合值)
推荐通过 Validators.Enum<T>() 或 Validators.Enum(typeof(T)) 工厂方法创建实例,便于未来扩展。
验证错误信息资源键
| 资源键 | 默认信息 |
|---|---|
EnumValidator_ValidationError | The field {0} must be a defined value of enum {1}. |
EnumValidator_ValidationError_SupportFlags | The field {0} must be a valid combination of values defined in enum {1}. |
8.4.22 EqualTo 相等验证器
功能描述
用于验证目标值是否与指定的值相等。
公开属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
CompareValue | object? | — | 用于比较的值(通过构造函数传入,不可变) |
使用示例
// 基础使用:验证是否等于固定值
var validator = new EqualToValidator("approved");
var isValid = validator.IsValid("pending"); // false
var validationResults = validator.GetValidationResults("rejected", "Status"); // 返回错误
validator.Validate("draft", "Status"); // 抛出 ValidationException
// 验证其他类型
var validator = new EqualToValidator(42);
var isValid = validator.IsValid(42); // true
var isValid = validator.IsValid(null); // true(null 被视为有效)
推荐通过 Validators.EqualTo(...) 工厂方法创建实例,便于未来扩展。
验证错误信息资源键
| 资源键 | 默认信息 |
|---|---|
EqualToValidator_ValidationError | The field {0} must be equal to '{1}'. |
8.4.23 Failure 固定失败验证器
功能描述
始终返回验证失败,仅用于输出指定错误信息。
公开属性
该验证器无额外公开属性。
使用示例
// 基础使用
var validator = new FailureValidator();
var isValid = validator.IsValid("any value"); // false
var validationResults = validator.GetValidationResults("data", "Field"); // 返回错误
validator.Validate("anything", "Field"); // 抛出 ValidationException
// 通常配合自定义错误信息使用
var validator = new FailureValidator();
validator.ErrorMessage = "This field is temporarily disabled.";
var isValid = validator.IsValid(null); // false
推荐通过 Validators.Failure() 工厂方法创建实例,便于未来扩展。
验证错误信息资源键
| 资源键 | 默认信息 |
|---|---|
ValidatorBase_ValidationError | The field {0} is invalid. |
8.4.24 FileExtensions 文件扩展名验证器
功能描述
用于验证文件名是否具有指定的扩展名(如 "jpg,png,gif"),支持自动忽略大小写和前导点号。
公开属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
Extensions | string | — | 允许的文件扩展名列表,以逗号分隔(通过构造函数传入,不可变) |
注:输入时可带或不带点号(如
"jpg"或".jpg"),系统会自动标准化处理。
使用示例
// 基础使用
var validator = new FileExtensionsValidator("jpg,jpeg,png");
var isValid = validator.IsValid("photo.gif"); // false
var validationResults = validator.GetValidationResults("image.bmp", "Avatar"); // 返回错误
validator.Validate("document.txt", "Avatar"); // 抛出 ValidationException
// 支持带点号或混合格式
var validator = new FileExtensionsValidator(".pdf, DOCX, xls");
var isValid = validator.IsValid("report.pdf"); // true
var isValid = validator.IsValid("data.XLS"); // true(自动忽略大小写)
推荐通过 Validators.FileExtensions(...) 工厂方法创建实例,便于未来扩展。
验证错误信息资源键
| 资源键 | 默认信息 |
|---|---|
FileExtensionsValidator_ValidationError | The {0} field only accepts files with the following extensions: {1}. |
8.4.25 GreaterThanOrEqualTo 大于等于验证器
功能描述
用于验证数值是否大于或等于指定的值。
公开属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
CompareValue | IComparable | — | 比较基准值(通过构造函数传入,不可变) |
注:仅当被验证值与
CompareValue类型兼容时才进行比较,否则视为无效。
使用示例
// 基础使用:验证数字是否 ≥ 100
var validator = new GreaterThanOrEqualToValidator(100);
var isValid = validator.IsValid(99); // false
var validationResults = validator.GetValidationResults(50, "Score"); // 返回错误
validator.Validate(0, "Score"); // 抛出 ValidationException
// 验证日期是否 ≥ 某个时间点
var validator = new GreaterThanOrEqualToValidator(new DateTime(2025, 1, 1));
var isValid = validator.IsValid(new DateTime(2026, 1, 1)); // true
var isValid = validator.IsValid("2024-12-31"); // false(类型不匹配)
推荐通过 Validators.GreaterThanOrEqualTo(...) 工厂方法创建实例,便于未来扩展。
验证错误信息资源键
| 资源键 | 默认信息 |
|---|---|
GreaterThanOrEqualToValidator_ValidationError | The field {0} must be greater than or equal to '{1}'. |
8.4.26 GreaterThan 大于验证器
功能描述
用于验证数值是否大于指定的值。
公开属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
CompareValue | IComparable | — | 比较基准值(通过构造函数传入,不可变) |
注:仅当被验证值与
CompareValue类型兼容时才进行比较,否则视为无效。
使用示例
// 基础使用:验证数字是否 > 0
var validator = new GreaterThanValidator(0);
var isValid = validator.IsValid(0); // false
var validationResults = validator.GetValidationResults(-5, "Quantity"); // 返回错误
validator.Validate(-1, "Quantity"); // 抛出 ValidationException
// 验证日期是否 > 某个时间点
var validator = new GreaterThanValidator(new DateTime(2025, 1, 1));
var isValid = validator.IsValid(new DateTime(2025, 1, 2)); // true
var isValid = validator.IsValid("2025-01-01"); // false(类型不匹配或等于)
推荐通过 Validators.GreaterThan(...) 工厂方法创建实例,便于未来扩展。
验证错误信息资源键
| 资源键 | 默认信息 |
|---|---|
GreaterThanValidator_ValidationError | The field {0} must be greater than '{1}'. |
8.4.27 HaveLength 固定长度验证器
功能描述
用于验证字符串、数组或集合的长度是否等于指定值。可选允许空值(长度为 0)。
公开属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
Length | int | — | 期望的固定长度(通过构造函数传入,不可变) |
AllowEmpty | bool | false | 是否允许空集合、数组或字符串(即长度为 0) |
使用示例
// 基础使用:必须恰好 6 个字符
var validator = new HaveLengthValidator(6);
var isValid = validator.IsValid("12345"); // false
var validationResults = validator.GetValidationResults("1234567", "Code"); // 返回错误
validator.Validate("1234", "Code"); // 抛出 ValidationException
// 允许空值
var validator = new HaveLengthValidator(8) { AllowEmpty = true };
var isValid = validator.IsValid(""); // true
var isValid = validator.IsValid(new int[8]); // true
推荐通过 Validators.HaveLength(...) 工厂方法创建实例,便于未来扩展。
验证错误信息资源键
| 资源键 | 默认信息 |
|---|---|
HaveLengthValidator_ValidationError | The field {0} must be a string or collection type with a length of exactly '{1}'. |
HaveLengthValidator_ValidationError_AllowEmpty | The field {0} must be empty or have a length of exactly '{1}'. |
8.4.28 IDCard 身份证号验证器
功能描述
用于验证字符串是否为符合中国大陆身份证号码格式(18 位,含校验码)的有效身份证号。
公开属性
该验证器无额外公开属性。
使用示例
// 基础使用
var validator = new IDCardValidator();
var isValid = validator.IsValid("11010119900307XXXX"); // false(格式不完整)
var validationResults = validator.GetValidationResults("123", "ID"); // 返回错误
validator.Validate("invalid-id", "ID"); // 抛出 ValidationException
// 验证有效身份证
var validator = new IDCardValidator();
var isValid = validator.IsValid("110101199003072316"); // true
var isValid = validator.IsValid("11010119900307231X"); // true(末位 X 合法)
推荐通过 Validators.IDCard() 工厂方法创建实例,便于未来扩展。
验证错误信息资源键
| 资源键 | 默认信息 |
|---|---|
IDCardValidator_ValidationError | The field {0} is not a valid Id card number format. |
8.4.29 IpAddress IP 地址验证器
功能描述
用于验证字符串是否为有效的 IPv4 或 IPv6 地址。默认仅支持 IPv4,可启用 IPv6 支持。
公开属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
AllowIPv6 | bool | false | 是否允许 IPv6 地址 |
使用示例
// 基础使用:仅验证 IPv4
var validator = new IpAddressValidator();
var isValid = validator.IsValid("192.168.1.256"); // false(无效 IPv4)
var validationResults = validator.GetValidationResults("invalid-ip", "Host"); // 返回错误
validator.Validate("10.0.0.1", "Host"); // true → 无异常
// 启用 IPv6 支持
var validator = new IpAddressValidator { AllowIPv6 = true };
var isValid = validator.IsValid("::1"); // true
var isValid = validator.IsValid("2001:db8::1"); // true
推荐通过 Validators.IpAddress() 工厂方法创建实例,便于未来扩展。
验证错误信息资源键
| 资源键 | 默认信息 |
|---|---|
IpAddressValidator_ValidationError | The field {0} is not a valid IPv4 address. |
IpAddressValidator_ValidationError_AllowIPv6 | The field {0} is not a valid IP address (IPv4 or IPv6). |
8.4.30 Json JSON 格式验证器
功能描述
用于验证字符串是否为有效的 JSON 对象({...})或数组([...])。
公开属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
AllowTrailingCommas | bool | false | 是否允许末尾多余逗号 |
使用示例
// 基础使用:严格 JSON 格式
var validator = new JsonValidator();
var isValid = validator.IsValid("{ name: 'test' }"); // false(缺少引号)
var validationResults = validator.GetValidationResults("invalid", "Payload"); // 返回错误
validator.Validate("[]", "Payload"); // true → 无异常
// 允许末尾逗号
var validator = new JsonValidator { AllowTrailingCommas = true };
var isValid = validator.IsValid(@"{""a"":1,""b"":2,}"); // true
var isValid = validator.IsValid(@"[""x"",""y"",]"); // true
推荐通过 Validators.Json() 工厂方法创建实例,便于未来扩展。
验证错误信息资源键
| 资源键 | 默认信息 |
|---|---|
JsonValidator_ValidationError | The {0} field must be a valid JSON object or array. |
8.4.31 Length 长度验证器
功能描述
用于验证字符串、数组或集合的长度是否在指定的最小值和最大值之间(含边界)。
公开属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
MinimumLength | int | — | 最小允许长度(通过构造函数传入,不可变) |
MaximumLength | int | — | 最大允许长度(通过构造函数传入,不可变) |
注:仅适用于字符串、数组、列表等可计算长度的类型。
使用示例
// 基础使用:长度必须在 2 到 10 之间
var validator = new LengthValidator(2, 10);
var isValid = validator.IsValid("A"); // false(长度不足)
var validationResults = validator.GetValidationResults("TooLongString", "Name"); // 返回错误
validator.Validate("", "Name"); // 抛出 ValidationException
// 验证集合
var validator = new LengthValidator(1, 5);
var isValid = validator.IsValid(new[] { "a", "b" }); // true
var isValid = validator.IsValid(new int[6]); // false(超出最大长度)
推荐通过 Validators.Length(...) 工厂方法创建实例,便于未来扩展。
验证错误信息资源键
| 资源键 | 默认信息 |
|---|---|
LengthValidator_ValidationError | The field {0} must be a string or collection type with a minimum length of '{1}' and maximum length of '{2}'. |
8.4.32 LessThanOrEqualTo 小于等于验证器
功能描述
用于验证数值是否小于或等于指定的值。
公开属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
CompareValue | IComparable | — | 比较基准值(通过构造函数传入,不可变) |
注:仅当被验证值与
CompareValue类型兼容时才进行比较,否则视为无效。
使用示例
// 基础使用:验证数字是否 ≤ 100
var validator = new LessThanOrEqualToValidator(100);
var isValid = validator.IsValid(101); // false
var validationResults = validator.GetValidationResults(150, "Score"); // 返回错误
validator.Validate(200, "Score"); // 抛出 ValidationException
// 验证日期是否 ≤ 某个时间点
var validator = new LessThanOrEqualToValidator(new DateTime(2025, 12, 31));
var isValid = validator.IsValid(new DateTime(2025, 6, 1)); // true
var isValid = validator.IsValid("2026-01-01"); // false(类型不匹配或超出)
推荐通过 Validators.LessThanOrEqualTo(...) 工厂方法创建实例,便于未来扩展。
验证错误信息资源键
| 资源键 | 默认信息 |
|---|---|
LessThanOrEqualToValidator_ValidationError | The field {0} must be less than or equal to '{1}'. |
8.4.33 LessThan 小于验证器
功能描述
用于验证数值是否小于指定的值。
公开属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
CompareValue | IComparable | — | 比较基准值(通过构造函数传入,不可变) |
注:仅当被验证值与
CompareValue类型兼容时才进行比较,否则视为无效。
使用示例
// 基础使用:验证数字是否 < 10
var validator = new LessThanValidator(10);
var isValid = validator.IsValid(10); // false
var validationResults = validator.GetValidationResults(15, "Count"); // 返回错误
validator.Validate(10, "Count"); // 抛出 ValidationException
// 验证日期是否 < 某个时间点
var validator = new LessThanValidator(new DateTime(2026, 1, 1));
var isValid = validator.IsValid(new DateTime(2025, 12, 31)); // true
var isValid = validator.IsValid("2026-01-01"); // false(类型不匹配或等于)
推荐通过 Validators.LessThan(...) 工厂方法创建实例,便于未来扩展。
验证错误信息资源键
| 资源键 | 默认信息 |
|---|---|
LessThanValidator_ValidationError | The field {0} must be less than '{1}'. |
8.4.34 MaxLength 最大长度验证器
功能描述
用于验证字符串、数组或集合的长度是否不超过指定的最大值。
公开属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
Length | int | — | 最大允许长度(通过构造函数传入,不可变) |
注:仅适用于字符串、数组、列表等可计算长度的类型。
使用示例
// 基础使用:最大长度为 50
var validator = new MaxLengthValidator(50);
var isValid = validator.IsValid(new string('x', 51)); // false
var validationResults = validator.GetValidationResults("This is too long...", "Description"); // 返回错误
validator.Validate("A".PadRight(51), "Description"); // 抛出 ValidationException
// 验证数组
var validator = new MaxLengthValidator(3);
var isValid = validator.IsValid(new[] { "a", "b" }); // true
var isValid = validator.IsValid(new int[4]); // false
推荐通过 Validators.MaxLength(...) 工厂方法创建实例,便于未来扩展。
验证错误信息资源键
| 资源键 | 默认信息 |
|---|---|
MaxLengthValidator_ValidationError | The field {0} must be a string or array type with a maximum length of '{1}'. |
8.4.35 Max 最大值验证器
功能描述
用于验证数值是否小于或等于指定的最大值。
公开属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
CompareValue | IComparable | — | 允许的最大值(通过构造函数传入,不可变) |
注:仅当被验证值与
CompareValue类型兼容时才进行比较,否则视为无效。
使用示例
// 基础使用:最大值为 100
var validator = new MaxValidator(100);
var isValid = validator.IsValid(101); // false
var validationResults = validator.GetValidationResults(150, "Score"); // 返回错误
validator.Validate(200, "Score"); // 抛出 ValidationException
// 验证日期不超过某个时间点
var validator = new MaxValidator(new DateTime(2025, 12, 31));
var isValid = validator.IsValid(new DateTime(2025, 6, 1)); // true
var isValid = validator.IsValid("2026-01-01"); // false(类型不匹配或超出)
推荐通过 Validators.Max(...) 工厂方法创建实例,便于未来扩展。
验证错误信息资源键
| 资源键 | 默认信息 |
|---|---|
MaxValidator_ValidationError | The field {0} must be less than or equal to '{1}'. |
8.4.36 MD5String MD5 字符串验证器
功能描述
用于验证字符串是否为有效的 MD5 哈希值(标准 32 位格式),可选支持 16 位截断格式。
公开属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
AllowShortFormat | bool | false | 是否允许 16 位截断的 MD5 格式 |
使用示例
// 基础使用:仅允许 32 位标准格式
var validator = new MD5StringValidator();
var isValid = validator.IsValid("d41d8cd98f00b204e9800998ecf8427e"); // true
var validationResults = validator.GetValidationResults("invalid-md5", "Hash"); // 返回错误
validator.Validate("short", "Hash"); // 抛出 ValidationException
// 允许 16 位或 32 位格式
var validator = new MD5StringValidator { AllowShortFormat = true };
var isValid = validator.IsValid("d41d8cd98f00b204"); // true(16 位)
var isValid = validator.IsValid("d41d8cd98f00b204e9800998ecf8427e"); // true(32 位)
推荐通过 Validators.MD5String() 工厂方法创建实例,便于未来扩展。
验证错误信息资源键
| 资源键 | 默认信息 |
|---|---|
MD5StringValidator_ValidationError | The field {0} is not a valid MD5 string. |
8.4.37 MinLength 最小长度验证器
功能描述
用于验证字符串、数组或集合的长度是否不小于指定的最小值。
公开属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
Length | int | — | 最小允许长度(通过构造函数传入,不可变) |
注:仅适用于字符串、数组、列表等可计算长度的类型。
使用示例
// 基础使用:最小长度为 5
var validator = new MinLengthValidator(5);
var isValid = validator.IsValid("1234"); // false
var validationResults = validator.GetValidationResults("Hi", "Username"); // 返回错误
validator.Validate("", "Username"); // 抛出 ValidationException
// 验证数组
var validator = new MinLengthValidator(2);
var isValid = validator.IsValid(new[] { "a", "b" }); // true
var isValid = validator.IsValid(new int[1]); // false
推荐通过 Validators.MinLength(...) 工厂方法创建实例,便于未来扩展。
验证错误信息资源键
| 资源键 | 默认信息 |
|---|---|
MinLengthValidator_ValidationError | The field {0} must be a string or array type with a minimum length of '{1}'. |
8.4.38 Min 最小值验证器
功能描述
用于验证数值是否大于或等于指定的最小值。
公开属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
CompareValue | IComparable | — | 允许的最小值(通过构造函数传入,不可变) |
注:仅当被验证值与
CompareValue类型兼容时才进行比较,否则视为无效。
使用示例
// 基础使用:最小值为 0
var validator = new MinValidator(0);
var isValid = validator.IsValid(-1); // false
var validationResults = validator.GetValidationResults(-5, "Quantity"); // 返回错误
validator.Validate(-10, "Quantity"); // 抛出 ValidationException
// 验证日期不早于某个时间点
var validator = new MinValidator(new DateTime(2020, 1, 1));
var isValid = validator.IsValid(new DateTime(2025, 1, 1)); // true
var isValid = validator.IsValid("2019-12-31"); // false(类型不匹配或小于)
推荐通过 Validators.Min(...) 工厂方法创建实例,便于未来扩展。
验证错误信息资源键
| 资源键 | 默认信息 |
|---|---|
MinValidator_ValidationError | The field {0} must be greater than or equal to '{1}'. |
8.4.39 Must 自定义条件验证器
功能描述
用于通过自定义委托(Func<T, bool> 或 Func<T, ValidationContext<T>, bool>)验证对象是否满足特定业务逻辑条件。支持在条件不满足时抛出带自定义信息的异常。
公开属性
该验证器通过构造函数传入条件委托,无额外公开属性。
使用示例
// 基础使用:简单条件
var validator = new MustValidator<User>(u => u.Age >= 18);
var user = new User { Age = 16 };
var isValid = validator.IsValid(user); // false
var validationResults = validator.GetValidationResults(user, "User"); // 返回错误
validator.Validate(user, "User"); // 抛出 ValidationException
// 高级使用:带上下文和自定义错误信息
var validator = new MustValidator<User>((u, ctx) =>
{
if (u.Age < 18)
{
return Must.WithMessage("{0} must be at least 18 years old.");
}
return true;
});
var user = new User { Age = 15 };
validator.Validate(user, new ValidationContext<User>(user) { DisplayName = "Profile" }); // 抛出自定义信息
推荐通过 Validators.Must(...) 工厂方法创建实例,便于未来扩展。
验证错误信息资源键
| 资源键 | 默认信息 |
|---|---|
ValidatorBase_ValidationError | The field {0} is invalid. |
注:若在条件委托中调用
Must.WithMessage(),将覆盖默认信息。
8.4.40 NotBlank 非空白字符串验证器
功能描述
用于验证值是否为非空且非空白的字符串或非空白字符(不接受仅包含空格、制表符、换行等空白字符的输入)。
公开属性
该验证器无额外公开属性。
使用示例
// 基础使用
var validator = new NotBlankValidator();
var isValid = validator.IsValid(" "); // false
var validationResults = validator.GetValidationResults("", "Name"); // 返回错误
validator.Validate("\t\n", "Name"); // 抛出 ValidationException
// 验证有效输入
var validator = new NotBlankValidator();
var isValid = validator.IsValid("John"); // true
var isValid = validator.IsValid('A'); // true
推荐通过 Validators.NotBlank() 工厂方法创建实例,便于未来扩展。
验证错误信息资源键
| 资源键 | 默认信息 |
|---|---|
NotBlankValidator_ValidationError | The field {0} cannot be empty or whitespace. |
8.4.41 NotEmpty 非空验证器
功能描述
用于验证值是否为非空的集合、数组或字符串(即长度大于 0)。null 值被视为有效。
公开属性
该验证器无额外公开属性。
使用示例
// 基础使用
var validator = new NotEmptyValidator();
var isValid = validator.IsValid(new List<int>()); // false(空集合)
var validationResults = validator.GetValidationResults("", "Name"); // 返回错误
validator.Validate(new int[0], "Items"); // 抛出 ValidationException
// 验证有效输入
var validator = new NotEmptyValidator();
var isValid = validator.IsValid("Hello"); // true
var isValid = validator.IsValid(new[] { 1, 2, 3 }); // true
推荐通过 Validators.NotEmpty() 工厂方法创建实例,便于未来扩展。
验证错误信息资源键
| 资源键 | 默认信息 |
|---|---|
NotEmptyValidator_ValidationError | The field {0} does not allow empty values. |
8.4.42 NotEqualTo 不相等验证器
功能描述
用于验证目标值是否不等于指定的值。
公开属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
CompareValue | object? | — | 用于比较的值(通过构造函数传入,不可变) |
使用示例
// 基础使用:不能等于 "admin"
var validator = new NotEqualToValidator("admin");
var isValid = validator.IsValid("admin"); // false
var validationResults = validator.GetValidationResults("admin", "Username"); // 返回错误
validator.Validate("admin", "Username"); // 抛出 ValidationException
// 验证其他类型
var validator = new NotEqualToValidator(0);
var isValid = validator.IsValid(1); // true
var isValid = validator.IsValid(null); // true(null 被视为有效)
推荐通过 Validators.NotEqualTo(...) 工厂方法创建实例,便于未来扩展。
验证错误信息资源键
| 资源键 | 默认信息 |
|---|---|
NotEqualToValidator_ValidationError | The field {0} cannot be equal to '{1}'. |
8.4.43 NotNull 非 null 验证器
功能描述
用于验证值是否不为 null。
公开属性
该验证器无额外公开属性。
使用示例
// 基础使用
var validator = new NotNullValidator();
var isValid = validator.IsValid(null); // false
var validationResults = validator.GetValidationResults(null, "Name"); // 返回错误
validator.Validate(null, "Name"); // 抛出 ValidationException
// 验证非 null 值
var validator = new NotNullValidator();
var isValid = validator.IsValid("Hello"); // true
var isValid = validator.IsValid(0); // true
推荐通过 Validators.NotNull() 工厂方法创建实例,便于未来扩展。
验证错误信息资源键
| 资源键 | 默认信息 |
|---|---|
NotNullValidator_ValidationError | The field {0} does not allow null values. |
8.4.44 Null null 验证器
功能描述
用于验证值是否为 null。
公开属性
该验证器无额外公开属性。
使用示例
// 基础使用
var validator = new NullValidator();
var isValid = validator.IsValid("not null"); // false
var validationResults = validator.GetValidationResults("value", "Field"); // 返回错误
validator.Validate(new object(), "Field"); // 抛出 ValidationException
// 验证 null 值
var validator = new NullValidator();
var isValid = validator.IsValid(null); // true
var isValid = validator.IsValid((string?)null); // true
推荐通过 Validators.Null() 工厂方法创建实例,便于未来扩展。
验证错误信息资源键
| 资源键 | 默认信息 |
|---|---|
NullValidator_ValidationError | The field {0} must be null. |
8.4.45 Password 密码验证器
功能描述
用于验证密码是否符合安全策略,支持普通模式(8–64 位,含字母和数字)和强密码模式(12–64 位,必须包含大小写字母、数字和特殊字符)。
公开属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
Strong | bool | false | 是否启用强密码验证模式 |
使用示例
// 基础使用:普通密码规则
var validator = new PasswordValidator();
var isValid = validator.IsValid("12345678"); // false(无字母)
var validationResults = validator.GetValidationResults("weak", "Password"); // 返回错误
validator.Validate("pass", "Password"); // 抛出 ValidationException
// 启用强密码模式
var validator = new PasswordValidator { Strong = true };
var isValid = validator.IsValid("SecurePass123!"); // true
var isValid = validator.IsValid("Weak123"); // false(缺少大写或特殊字符)
推荐通过 Validators.Password() 工厂方法创建实例,便于未来扩展。
验证错误信息资源键
| 资源键 | 默认信息 |
|---|---|
PasswordValidator_ValidationError | The field {0} has an invalid password format. It must be 8 to 64 characters long and contain at least one letter and one number. |
PasswordValidator_ValidationError_Strong | The field {0} has an invalid password format. It must be 12 to 64 characters long and contain uppercase letters, lowercase letters, numbers, and special characters. |
8.4.46 PhoneNumber 手机号(中国)验证器
功能描述
用于验证字符串是否为有效的中国大陆手机号码,支持带或不带国际区号(如 13800138000、+8613800138000 或 008613800138000)。
公开属性
该验证器无额外公开属性。
使用示例
// 基础使用
var validator = new PhoneNumberValidator();
var isValid = validator.IsValid("1380013800"); // false(10 位)
var validationResults = validator.GetValidationResults("12345678901", "Phone"); // 返回错误
validator.Validate("invalid-phone", "Phone"); // 抛出 ValidationException
// 支持国际格式
var validator = new PhoneNumberValidator();
var isValid = validator.IsValid("13800138000"); // true
var isValid = validator.IsValid("+8613912345678"); // true
var isValid = validator.IsValid("008615012345678"); // true
推荐通过 Validators.PhoneNumber() 工厂方法创建实例,便于未来扩展。
验证错误信息资源键
| 资源键 | 默认信息 |
|---|---|
PhoneNumberValidator_ValidationError | The field {0} is not a valid phone number. |
8.4.47 PostalCode 邮政编码(中国)验证器
功能描述
用于验证字符串是否为有效的中国大陆邮政编码(6 位数字,符合中国邮政区域分配规则)。
公开属性
该验证器无额外公开属性。
使用示例
// 基础使用
var validator = new PostalCodeValidator();
var isValid = validator.IsValid("10000"); // false(5 位)
var validationResults = validator.GetValidationResults("123456", "Zip"); // 返回错误(123456 不在有效区段)
validator.Validate("000000", "Zip"); // 抛出 ValidationException
// 验证有效邮编
var validator = new PostalCodeValidator();
var isValid = validator.IsValid("100000"); // true
var isValid = validator.IsValid("518000"); // true(深圳)
推荐通过 Validators.PostalCode() 工厂方法创建实例,便于未来扩展。
验证错误信息资源键
| 资源键 | 默认信息 |
|---|---|
PostalCodeValidator_ValidationError | The field {0} is not a valid postal code. |
8.4.48 Range 数值范围验证器
功能描述
用于验证数值是否在指定的最小值和最大值之间(可配置是否包含边界)。支持整数、浮点数及通过字符串指定的任意数值类型。
公开属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
Minimum | object | — | 允许的最小值(构造函数传入,不可变) |
Maximum | object | — | 允许的最大值(构造函数传入,不可变) |
OperandType | Type | — | 数值类型(如 typeof(int)、typeof(double) 等) |
MinimumIsExclusive | bool | false | 是否排除最小值(即 > 而非 ≥) |
MaximumIsExclusive | bool | false | 是否排除最大值(即 < 而非 ≤) |
ParseLimitsInInvariantCulture | bool | false | 是否使用固定区域性解析 Minimum/Maximum 字符串 |
ConvertValueInInvariantCulture | bool | false | 是否使用固定区域性转换被验证值 |
注:
Minimum、Maximum和OperandType由构造函数确定,不可修改;其余属性可在实例创建后设置。
使用示例
// 基础使用:整数范围 [0, 100]
var validator = new RangeValidator(0, 100);
var isValid = validator.IsValid(-1); // false
var validationResults = validator.GetValidationResults(150, "Score"); // 返回错误
validator.Validate(200, "Score"); // 抛出 ValidationException
// 排除边界:(0, 10)
var validator = new RangeValidator(0, 10)
{
MinimumIsExclusive = true,
MaximumIsExclusive = true
};
var isValid = validator.IsValid(0); // false
var isValid = validator.IsValid(10); // false
var isValid = validator.IsValid(5); // true
推荐通过 Validators.Range(...) 工厂方法创建实例,便于未来扩展。
验证错误信息资源键
| 资源键 | 默认信息 |
|---|---|
RangeValidator_ValidationError | The field {0} must be between '{1}' and '{2}'. |
RangeValidator_ValidationError_MinExclusive | The field {0} must be between '{1}' exclusive and '{2}'. |
RangeValidator_ValidationError_MaxExclusive | The field {0} must be between '{1}' and '{2}' exclusive. |
RangeValidator_ValidationError_MinExclusive_MaxExclusive | The field {0} must be between '{1}' exclusive and '{2}' exclusive. |
8.4.49 RegularExpression 正则表达式验证器
功能描述
用于验证字符串是否匹配指定的正则表达式模式。
公开属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
Pattern | string | — | 正则表达式模式(通过构造函数传入,不可变) |
MatchTimeoutInMilliseconds | int | 2000 | 单次匹配操作的超时时间(毫秒),可防止正则表达式回溯攻击 |
使用示例
// 基础使用:仅允许数字
var validator = new RegularExpressionValidator(@"^\d+$");
var isValid = validator.IsValid("abc"); // false
var validationResults = validator.GetValidationResults("12a3", "Code"); // 返回错误
validator.Validate("12.34", "Code"); // 抛出 ValidationException
// 自定义超时
var validator = new RegularExpressionValidator(@"^[A-Za-z0-9]{6,20}$")
{
MatchTimeoutInMilliseconds = 5000
};
var isValid = validator.IsValid("User123"); // true
var isValid = validator.IsValid("user@name"); // false
推荐通过 Validators.RegularExpression(...) 工厂方法创建实例,便于未来扩展。
验证错误信息资源键
| 资源键 | 默认信息 |
|---|---|
RegularExpressionValidator_ValidationError | The field {0} must match the regular expression '{1}'. |
8.4.50 Required 必填验证器
功能描述
用于验证值是否已提供(非 null)。默认情况下,空字符串也被视为无效,但可通过配置允许。
公开属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
AllowEmptyStrings | bool | false | 是否将空字符串("")视为有效值 |
注:该验证器具有高优先级(
Priority = 10),通常在其他验证前执行。
使用示例
// 基础使用:不允许 null 或空字符串
var validator = new RequiredValidator();
var isValid = validator.IsValid(null); // false
var validationResults = validator.GetValidationResults("", "Name"); // 返回错误
validator.Validate(" ", "Name"); // true(空白字符串视为非空)
// 允许空字符串
var validator = new RequiredValidator { AllowEmptyStrings = true };
var isValid = validator.IsValid(""); // true
var isValid = validator.IsValid(null); // false
推荐通过 Validators.Required() 工厂方法创建实例,便于未来扩展。
验证错误信息资源键
| 资源键 | 默认信息 |
|---|---|
RequiredValidator_ValidationError | The {0} field is required. |
8.4.51 Single 单项验证器
功能描述
用于验证集合、数组或字符串是否仅包含一个元素(长度为 1)。null 值被视为有效。
公开属性
该验证器无额外公开属性。
使用示例
// 基础使用
var validator = new SingleValidator();
var isValid = validator.IsValid(new List<int>()); // false(空集合)
var validationResults = validator.GetValidationResults(new[] { 1, 2 }, "Items"); // 返回错误(多于一项)
validator.Validate("AB", "Code"); // 抛出 ValidationException
// 验证有效输入
var validator = new SingleValidator();
var isValid = validator.IsValid(new[] { "A" }); // true
var isValid = validator.IsValid("X"); // true(单字符字符串)
推荐通过 Validators.Single() 工厂方法创建实例,便于未来扩展。
验证错误信息资源键
| 资源键 | 默认信息 |
|---|---|
SingleValidator_ValidationError | The field {0} only allows a single item. |
8.4.52 StartsWith 开头字符串验证器
功能描述
用于验证字符串是否以指定的字符或字符串开头。
公开属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
SearchValue | string | — | 检索的值(通过构造函数传入,不可变) |
Comparison | StringComparison | StringComparison.Ordinal | 字符串比较方式 |
使用示例
// 基础使用
var validator = new StartsWithValidator("https://");
var isValid = validator.IsValid("http://example.com"); // false
var validationResults = validator.GetValidationResults("ftp://site", "Url"); // 返回错误
validator.Validate("file://path", "Url"); // 抛出 ValidationException
// 自定义比较方式
var validator = new StartsWithValidator("ID") { Comparison = StringComparison.OrdinalIgnoreCase };
var isValid = validator.IsValid("id123"); // true
var isValid = validator.IsValid("Id_456"); // true
推荐通过 Validators.StartsWith(...) 工厂方法创建实例,便于未来扩展。
验证错误信息资源键
| 资源键 | 默认信息 |
|---|---|
StartsWithValidator_ValidationError | The field {0} does not start with the string '{1}'. |
8.4.53 StringContains 字符串包含验证器
功能描述
用于验证字符串是否包含指定的字符或子字符串。
公开属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
SearchValue | string | — | 要查找的字符或子字符串(通过构造函数传入,不可变) |
Comparison | StringComparison | StringComparison.Ordinal | 字符串比较方式 |
使用示例
// 基础使用
var validator = new StringContainsValidator("@");
var isValid = validator.IsValid("userexample.com"); // false
var validationResults = validator.GetValidationResults("user#example", "Email"); // 返回错误
validator.Validate("user.example", "Email"); // 抛出 ValidationException
// 忽略大小写
var validator = new StringContainsValidator("ADMIN") { Comparison = StringComparison.OrdinalIgnoreCase };
var isValid = validator.IsValid("system_admin"); // true
var isValid = validator.IsValid("UserAdminRole"); // true
推荐通过 Validators.StringContains(...) 工厂方法创建实例,便于未来扩展。
验证错误信息资源键
| 资源键 | 默认信息 |
|---|---|
StringContainsValidator_ValidationError | The field {0} does not contain the string '{1}'. |
8.4.54 StringLength 字符串长度验证器
功能描述
用于验证字符串长度是否在指定范围内。默认仅设置最大长度,可额外配置最小长度。
公开属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
MaximumLength | int | — | 最大允许长度(通过构造函数传入,不可变) |
MinimumLength | int | 0 | 最小允许长度(可后续设置) |
注:仅适用于字符串类型。若同时设置了最小和最大长度,将使用包含两者的错误信息。
使用示例
// 基础使用:最大长度为 10
var validator = new StringLengthValidator(10);
var isValid = validator.IsValid("12345678901"); // false
var validationResults = validator.GetValidationResults("TooLongString", "Name"); // 返回错误
validator.Validate("A".PadRight(11), "Name"); // 抛出 ValidationException
// 设置最小和最大长度
var validator = new StringLengthValidator(20) { MinimumLength = 5 };
var isValid = validator.IsValid("Hi"); // false(小于最小长度)
var isValid = validator.IsValid("ValidInput"); // true
推荐通过 Validators.StringLength(...) 工厂方法创建实例,便于未来扩展。
验证错误信息资源键
| 资源键 | 默认信息 |
|---|---|
StringLengthValidator_ValidationError | The field {0} must be a string with a maximum length of '{1}'. |
StringLengthValidator_ValidationError_MinimumLength | The field {0} must be a string with a minimum length of '{2}' and a maximum length of '{1}'. |
8.4.55 StringNotContains 字符串不包含验证器
功能描述
用于验证字符串是否不包含指定的字符或子字符串。
公开属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
SearchValue | string | — | 禁止出现的字符或子字符串(通过构造函数传入,不可变) |
Comparison | StringComparison | StringComparison.Ordinal | 字符串比较方式 |
使用示例
// 基础使用:禁止包含 "<script>"
var validator = new StringNotContainsValidator("<script>");
var isValid = validator.IsValid("Hello <script>alert(1)</script>"); // false
var validationResults = validator.GetValidationResults("Click <script>", "Content"); // 返回错误
validator.Validate("Run<script>", "Content"); // 抛出 ValidationException
// 忽略大小写禁止关键词
var validator = new StringNotContainsValidator("ADMIN") { Comparison = StringComparison.OrdinalIgnoreCase };
var isValid = validator.IsValid("System admin panel"); // false
var isValid = validator.IsValid("User dashboard"); // true
推荐通过 Validators.StringNotContains(...) 工厂方法创建实例,便于未来扩展。
验证错误信息资源键
| 资源键 | 默认信息 |
|---|---|
StringNotContainsValidator_ValidationError | The field {0} must not contain the string '{1}'. |
8.4.56 StrongPassword 强密码验证器
功能描述
用于验证密码是否符合强密码策略:长度为 12–64 位,且必须包含大写字母、小写字母、数字和特殊字符(如 !@#$%^&*)。
公开属性
该验证器无额外公开属性(内部固定启用
Strong = true)。
使用示例
// 基础使用
var validator = new StrongPasswordValidator();
var isValid = validator.IsValid("weak123"); // false(缺少大写和特殊字符)
var validationResults = validator.GetValidationResults("Pass123!", "Password"); // 返回错误(长度不足 12)
validator.Validate("Short1!", "Password"); // 抛出 ValidationException
// 验证强密码
var validator = new StrongPasswordValidator();
var isValid = validator.IsValid("SecurePass123!"); // true
var isValid = validator.IsValid("MyP@ssw0rd2025#"); // true
推荐通过 Validators.StrongPassword() 工厂方法创建实例,便于未来扩展。
验证错误信息资源键
| 资源键 | 默认信息 |
|---|---|
PasswordValidator_ValidationError_Strong | The field {0} has an invalid password format. It must be 12 to 64 characters long and contain uppercase letters, lowercase letters, numbers, and special characters. |
8.4.57 Telephone 座机(电话)验证器
功能描述
用于验证字符串是否为有效的中国大陆座机号码格式,支持带或不带区号及分机号(如 010-12345678、021-87654321-123 等)。
公开属性
该验证器无额外公开属性。
使用示例
// 基础使用
var validator = new TelephoneValidator();
var isValid = validator.IsValid("123456789"); // false(无区号且位数不符)
var validationResults = validator.GetValidationResults("010-1234567", "Phone"); // 返回错误(本地号不足 8 位)
validator.Validate("invalid-phone", "Phone"); // 抛出 ValidationException
// 验证有效座机
var validator = new TelephoneValidator();
var isValid = validator.IsValid("010-12345678"); // true
var isValid = validator.IsValid("021-87654321-123"); // true(含分机)
var isValid = validator.IsValid("400-123-4567"); // false(不符合座机格式)
推荐通过 Validators.Telephone() 工厂方法创建实例,便于未来扩展。
验证错误信息资源键
| 资源键 | 默认信息 |
|---|---|
TelephoneValidator_ValidationError | The field {0} is not a valid telephone. |
8.4.58 TimeOnly 时间验证器
功能描述
用于验证值是否为有效的 TimeOnly 类型或符合指定格式的时间字符串。
公开属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
Formats | string[] | — | 允许的时间格式(如 "HH:mm:ss") |
Provider | IFormatProvider? | CultureInfo.InvariantCulture | 格式提供器 |
Style | DateTimeStyles | DateTimeStyles.None | 日期解析样式,需与 Provider 搭配使用 |
注:
Formats通过构造函数传入,不可变;Provider和Style可在实例创建后修改。
使用示例
// 基础使用:允许任意标准时间格式
var validator = new TimeOnlyValidator();
var isValid = validator.IsValid("14:30:00"); // true
var validationResults = validator.GetValidationResults("25:00:00", "Time"); // 返回错误(无效时间)
validator.Validate("invalid", "Time"); // 抛出 ValidationException
// 指定允许的格式
var validator = new TimeOnlyValidator("HH:mm", "hh:mm tt")
{
Provider = CultureInfo.InvariantCulture,
Style = DateTimeStyles.None
};
var isValid = validator.IsValid("14:30"); // true
var isValid = validator.IsValid("02:30 PM"); // true
推荐通过 Validators.TimeOnly(...) 工厂方法创建实例,便于未来扩展。
验证错误信息资源键
| 资源键 | 默认信息 |
|---|---|
TimeOnlyValidator_ValidationError | The field {0} must be a valid time. |
TimeOnlyValidator_ValidationError_Formats | The field {0} must be a valid time in the following format(s): {1}. |
8.4.59 Url URL 地址验证器
功能描述
用于验证字符串是否为有效的 HTTP、HTTPS(默认)或 FTP(可选)协议的完整 URL 地址。
公开属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
SupportsFtp | bool | false | 是否允许 FTP 协议 |
注:URL 必须包含有效主机名(如
http://example.com),不接受http:///path等无效格式。
使用示例
// 基础使用:仅支持 HTTP/HTTPS
var validator = new UrlValidator();
var isValid = validator.IsValid("ftp://files.example.com"); // false
var validationResults = validator.GetValidationResults("invalid-url", "Link"); // 返回错误
validator.Validate("http:///missing-host", "Link"); // 抛出 ValidationException
// 启用 FTP 支持
var validator = new UrlValidator { SupportsFtp = true };
var isValid = validator.IsValid("https://api.example.com"); // true
var isValid = validator.IsValid("ftp://download.site/file.zip"); // true
推荐通过 Validators.Url() 工厂方法创建实例,便于未来扩展。
验证错误信息资源键
| 资源键 | 默认信息 |
|---|---|
UrlValidator_ValidationError | The {0} field is not a valid fully-qualified http, https URL. |
UrlValidator_ValidationError_SupportsFtp | The {0} field is not a valid fully-qualified http, https, or ftp URL. |
8.4.60 UserName 用户名验证器
功能描述
用于验证用户名是否符合安全命名规范:长度为 4–16 位,以字母开头,仅允许字母、数字、下划线(_)和连字符(-),且不能包含空格、其他特殊字符或连续的特殊字符(如 __ 或 --),结尾必须为字母或数字。
公开属性
该验证器无额外公开属性。
使用示例
// 基础使用
var validator = new UserNameValidator();
var isValid = validator.IsValid("user__name"); // false(连续下划线)
var validationResults = validator.GetValidationResults("123user", "Username"); // 返回错误(未以字母开头)
validator.Validate("user name", "Username"); // 抛出 ValidationException(含空格)
// 验证有效用户名
var validator = new UserNameValidator();
var isValid = validator.IsValid("john_doe"); // true
var isValid = validator.IsValid("Admin-01"); // true
推荐通过 Validators.UserName() 工厂方法创建实例,便于未来扩展。
验证错误信息资源键
| 资源键 | 默认信息 |
|---|---|
UserNameValidator_ValidationError | The field {0} is not a valid username. |
8.4.61 ValidatorProxy 验证器代理
功能描述
用于动态创建并代理另一个验证器实例,支持在运行时配置其属性或构造参数,适用于需要延迟初始化、依赖注入或上下文感知验证的场景。
公开属性
该验证器本身不直接暴露业务属性,而是通过
Configure方法将配置转发给被代理的验证器。
使用示例
// 基础代理:包装一个 EmailAddressValidator
var proxy = new ValidatorProxy<EmailAddressValidator>();
var isValid = proxy.IsValid("user@example.com"); // true
var validationResults = proxy.GetValidationResults("invalid", "Email"); // 返回错误
proxy.Validate("bad-email", "Email"); // 抛出 ValidationException
// 配置被代理验证器
var proxy = new ValidatorProxy<RangeValidator>(0, 100)
.Configure(v => v.MinimumIsExclusive = true);
var isValid = proxy.IsValid(0); // false(已排除最小值)
高级用法:对象级代理(带上下文)
// 根据对象动态创建验证器
var proxy = new ValidatorProxy<User, RangeValidator>(
user => user.Age, // 被验证的值:Age 属性
(user, ctx) => new object[] { 0, user.MaxAllowedAge } // 动态构造参数
).Configure(v => v.MinimumIsExclusive = false);
var user = new User { Age = 25, MaxAllowedAge = 30 };
var isValid = proxy.IsValid(user, new ValidationContext<User>(user)); // true
虽然 ValidatorProxy 通常用于高级场景,但若需统一入口,可通过自定义扩展方法封装。
验证错误信息资源键
由被代理的验证器决定,代理本身不定义独立错误信息。
8.4.62 Composite 组合验证器
功能描述
用于将多个验证器组合为一个整体,并支持三种验证模式:
- FailFast(默认):任一验证失败即停止,返回失败结果;
- All:所有验证器必须全部通过;
- Any:任意一个验证器通过即视为整体通过。
公开属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
Mode | CompositeMode | CompositeMode.FailFast | 验证执行模式 |
使用示例
// 基础使用:所有规则必须通过
var validator = new CompositeValidator<User>(builder =>
{
builder.Required().WithMessage("用户名不能为空");
builder.StringLength(3, 20).WithMessage("用户名长度必须在 3-20 之间");
});
var user = new User { Name = "" };
var isValid = validator.IsValid(user, new ValidationContext<User>(user)); // false
validator.Validate(user, new ValidationContext<User>(user)); // 抛出 ValidationException
// 使用 Any 模式:满足其一即可
var validator = new CompositeValidator<User>(builder =>
{
builder.EmailAddress();
builder.PhoneNumber();
}).UseRuleMode(RuleMode.Any);
var user1 = new User { Contact = "user@example.com" }; // 通过(邮箱有效)
var user2 = new User { Contact = "13800138000" }; // 通过(手机号有效)
var user3 = new User { Contact = "invalid" }; // 失败
推荐通过 Validators.Composite<T>(Action<FluentValidatorBuilder<T>>) 工厂方法创建实例,便于未来扩展。
验证错误信息资源键
默认使用各子验证器的错误信息。若设置了
ErrorMessage,则在结果首部插入自定义信息,其默认资源键为:
| 资源键 | 默认信息 |
|---|---|
ValidatorBase_ValidationError | The field {0} is invalid. |
8.4.63 Conditional 条件验证器
功能描述
用于根据运行时条件动态选择一组验证规则执行。支持多个条件分支,以及一个可选的默认规则(当所有条件都不满足时使用)。
公开属性
该验证器通过
ConditionBuilder<T>链式构建,无直接公开属性。
使用示例
// 基础使用:根据用户类型选择不同规则
var validator = new ConditionalValidator<User>(builder =>
{
builder.When(u => u.Type == UserType.Admin)
.Then(v => v.Required().EmailAddress());
builder.When(u => u.Type == UserType.Guest)
.Then(v => v.StringLength(1, 10));
builder.Otherwise(v => v.Required().UserName());
});
var admin = new User { Type = UserType.Admin, Email = "" };
validator.Validate(admin, new ValidationContext<User>(admin)); // 抛出 Required/Email 错误
var guest = new User { Type = UserType.Guest, Name = "A".PadRight(11) };
validator.Validate(guest, new ValidationContext<User>(guest)); // 抛出 StringLength 错误
// 仅返回错误信息(不执行验证)
var validator = new ConditionalValidator<Order>(builder =>
{
builder.When(o => o.Amount <= 0)
.ThenMessage("订单金额必须大于 0");
builder.OtherwiseMessage("未知订单状态");
});
推荐通过 Validators.Conditional<T>(Action<ConditionBuilder<T>>) 工厂方法创建实例,便于未来扩展。
验证错误信息资源键
默认使用各子验证器的错误信息。若在
ThenMessage或OtherwiseMessage中设置了自定义信息,则直接使用该信息;若在ConditionalValidator上设置了ErrorMessage,则在结果首部插入:
| 资源键 | 默认信息 |
|---|---|
ValidatorBase_ValidationError | The field {0} is invalid. |
8.4.64 Comparison 比较验证器抽象基类
功能描述
为所有基于值比较的验证器(如 GreaterThan、LessThanOrEqualTo 等)提供统一的基类。它封装了空值处理、类型匹配检查和错误信息格式化逻辑,要求派生类实现具体的比较逻辑。
公开属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
CompareValue | IComparable | — | 用于比较的基准值(通过构造函数传入,不可变) |
使用示例
该类为抽象基类,不直接用于实例化,而是作为以下验证器的父类:
GreaterThanValidatorGreaterThanOrEqualToValidatorLessThanValidatorLessThanOrEqualToValidatorMaxValidatorMinValidator
// 示例:创建一个自定义比较验证器
public class NotEqualValidator : ComparisonValidator
{
public NotEqualValidator(IComparable compareValue)
: base(compareValue, nameof(ValidationMessages.NotEqualValidator_ValidationError))
{
}
protected override bool IsValid(IComparable value, IValidationContext? validationContext) =>
IsTypeMatchedToCompareValue(value) && value.CompareTo(CompareValue) != 0;
}
// 使用
var validator = new NotEqualValidator(0);
var isValid = validator.IsValid(1); // true
此基类确保所有比较操作仅在类型一致时进行,避免跨类型比较导致的意外行为或异常。
验证错误信息资源键
由具体派生类指定,通常格式为:
| 资源键(示例) | 默认信息(示例) |
|---|---|
{ValidatorName}_ValidationError | The field {0} must be {condition} '{1}'. |
8.4.65 NumericComparison 数值比较验证器抽象基类
功能描述
为需要将输入值和比较基准值统一转换为 decimal 类型后再进行比较的验证器提供抽象基类。适用于需处理多种数值类型(如 int、float、double)并确保精度一致性的场景。
公开属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
CompareValue | IComparable | — | 原始比较值(通过构造函数传入,不可变) |
使用示例
// 自定义一个“必须为正数”的验证器
public class PositiveNumberValidator : NumericComparisonValidator
{
public PositiveNumberValidator()
: base(0m, nameof(ValidationMessages.PositiveNumberValidator_ValidationError))
{
}
protected override bool IsValid(decimal value, decimal compareValue) => value > compareValue;
}
// 使用
var validator = new PositiveNumberValidator();
var isValid = validator.IsValid(5); // true
var isValid = validator.IsValid(-1.5); // false
var isValid = validator.IsValid(0); // false
- 类型泛化:自动将
int、long、float、double、decimal等转换为decimal,避免类型不匹配。 - 精度安全:使用
decimal作为中间类型,适合金融、计量等对精度敏感的场景。 - 简化实现:派生类只需实现
IsValid(decimal, decimal),无需处理类型转换逻辑。
验证错误信息资源键
由具体派生类指定,通常格式为:
| 资源键(示例) | 默认信息(示例) |
|---|---|
{ValidatorName}_ValidationError | The field {0} must be {condition} '{1}'. |
8.5 自定义验证器
文档编写中....