.NET 7嵌套多态DTO必填字段验证失效问题求助
解决.NET 7嵌套多态DTO必填字段验证失效问题
问题背景
在.NET 7中使用嵌套多态DTO(通过JsonPolymorphic和JsonDerivedType标记)时,派生类的必填字段无法触发默认空值验证。例如ListValueDto和StringValueDto中的Value属性,即使设为非可空类型或添加[JsonRequired],提交null值仍会返回200响应;但顶级类(如ValueDto的Test属性)的验证却能正常生效。
原因分析
ASP.NET Core默认模型验证在处理嵌套多态对象时,只会校验父类(ValueDto)的属性,不会自动递归验证派生类的属性。只有当多态类作为顶级参数直接传入控制器时,验证逻辑才会正确触发派生类的属性校验。
解决方案
方法一:实现IValidatableObject接口
在派生类中手动编写验证逻辑,强制校验Value属性的非空性:
public class ListValueDto : ValueDto, IValidatableObject { public List<string> Value { get; set; } public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) { if (Value == null) { yield return new ValidationResult( "ListValueDto的Value字段不能为空", new[] { nameof(Value) }); } } } public class StringValueDto : ValueDto, IValidatableObject { public string Value { get; set; } public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) { if (string.IsNullOrEmpty(Value)) { yield return new ValidationResult( "StringValueDto的Value字段不能为空或空白", new[] { nameof(Value) }); } } }
控制器中只需保留默认模型状态判断即可([ApiController]会自动触发验证):
[HttpPost(Name = "PostTest")] public IActionResult PostTest([FromBody] ParentDto dto) { if (!ModelState.IsValid) { return BadRequest(ModelState); } return Ok(); }
方法二:使用FluentValidation库
FluentValidation对多态类型的验证支持更灵活,能精准覆盖派生类的校验逻辑:
- 安装NuGet包:
FluentValidation.AspNetCore - 为派生类创建验证器:
public class ListValueDtoValidator : AbstractValidator<ListValueDto> { public ListValueDtoValidator() { RuleFor(x => x.Value).NotNull().WithMessage("ListValueDto的Value不能为空"); } } public class StringValueDtoValidator : AbstractValidator<StringValueDto> { public StringValueDtoValidator() { RuleFor(x => x.Value).NotEmpty().WithMessage("StringValueDto的Value不能为空或空白"); } }
- 在Program.cs中注册验证器:
builder.Services.AddControllers() .AddFluentValidation(fv => fv.RegisterValidatorsFromAssemblyContaining<Program>());
配置完成后,提交包含null的Value时会自动返回400响应及错误信息。
方法三:手动触发派生类验证
在控制器中针对不同派生类型手动校验属性,适合简单场景:
[HttpPost(Name = "PostTest")] public IActionResult PostTest([FromBody] ParentDto dto) { if (dto.SomeProperty is ListValueDto listDto) { if (listDto.Value == null) { ModelState.AddModelError("SomeProperty.Value", "ListValueDto的Value不能为空"); } } else if (dto.SomeProperty is StringValueDto stringDto) { if (string.IsNullOrEmpty(stringDto.Value)) { ModelState.AddModelError("SomeProperty.Value", "StringValueDto的Value不能为空或空白"); } } if (!ModelState.IsValid) { return BadRequest(ModelState); } return Ok(); }
此方法扩展性较差,新增派生类型时需修改控制器代码。
内容的提问来源于stack exchange,提问作者XVar
相关产品推荐
相关产品推荐

