ApiController未标记[Required]的嵌套类列表返回400错误问题
问题根因
这是[ApiController]特性的默认框架行为,和你是否手动添加[Required]特性没有直接关系:
- .NET 6+ 项目默认开启不可为null引用类型(NRT)校验,只要项目启用了NRT上下文,所有未标记
?的引用类型属性,都会被框架隐式添加[Required]校验规则,无需手动声明 [ApiController]内置了自动模型验证过滤器,模型绑定完成后如果校验不通过,会直接返回400 BadRequest,不会进入接口业务逻辑- 如果你定义的
NestedClass中,属性都是未标记可空的引用类型,或是未标记可空的值类型,就会出现空列表、属性缺省值时触发校验失败的情况。
排查思路
按以下顺序逐一排查即可定位问题:
- 检查项目根目录的
.csproj文件,确认是否存在<Nullable>enable</Nullable>配置,该配置开启后非空引用类型的隐式必填校验就会生效 - 检查Program.cs(或旧版本的Startup.cs)中的控制器配置,确认
SuppressImplicitRequiredAttributeForNonNullableReferenceTypes选项是否被设置为false,该值默认即为false,代表启用隐式必填校验 - 检查
NestedClass的类定义,确认所有属性的类型声明:未加?的string、自定义类等引用类型,以及未加?的int、DateTime等值类型,都会被判定为必填 - 检查项目中是否添加了自定义模型验证提供者、全局动作过滤器,这类代码也可能注入全局必填校验规则。
解决建议
根据实际业务场景选择对应方案即可:
方案1:正确声明可空类型(推荐,符合.NET官方开发规范)
如果属性允许为空/缺省,直接在类型后添加?将其声明为可空类型,框架就不会对这些属性执行隐式必填校验,示例代码:
public class NestedClass { // 允许属性缺省/为空时,在类型后加?标记 public string? NestedPropertyA { get; set; } public int? NestedPropertyB { get; set; } } public class TestModel { // 如果允许NestedClasses字段本身传null,可给List类型加? // 如果仅允许传空列表[]、不允许传null,则不需要给List加? public List<NestedClass>? NestedClasses { get; set; } public string? TestProperty { get; set; } }
提示:如果仅传入空列表
[],只要列表元素的类型属性都正确标记了可空性,不会触发校验失败。
方案2:全局关闭非空引用类型的隐式必填校验
如果不需要NRT带来的隐式校验能力,可以在配置控制器服务时关闭该规则,关闭后只有手动添加[Required]特性的属性才会触发必填校验:
builder.Services.AddControllers() .ConfigureApiBehaviorOptions(options => { options.SuppressImplicitRequiredAttributeForNonNullableReferenceTypes = true; });
方案3:关闭ApiController自动400响应
如果需要完全自定义模型校验的逻辑和返回格式,可以关闭内置的自动校验返回逻辑,自行在接口代码中处理校验结果:
builder.Services.AddControllers() .ConfigureApiBehaviorOptions(options => { // 关闭校验不通过自动返回400的行为 options.SuppressModelStateInvalidFilter = true; });
关闭后可在接口内通过判断ModelState.IsValid属性,自行编写校验失败的返回逻辑。
内容的提问来源于stack exchange,提问作者Leito7
相关产品推荐
相关产品推荐

