You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.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对多态类型的验证支持更灵活,能精准覆盖派生类的校验逻辑:

  1. 安装NuGet包:FluentValidation.AspNetCore
  2. 为派生类创建验证器:
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不能为空或空白");
    }
}
  1. 在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 07:57:05