为何未添加BindRequired特性的[FromQuery]参数仍返回必填验证错误?
嗨,我之前也踩过这个坑!这个问题其实和ASP.NET Core从.NET 6开始默认启用的**Nullable Reference Types(可空引用类型)**特性有关,不是你漏加了什么配置,而是框架的自动验证在起作用。
问题原因
当你的项目启用了Nullable(通常在.csproj里配置了<Nullable>enable</Nullable>),对于[FromQuery]、[FromRoute]这类绑定源的非可空引用类型参数(比如你的string type),ASP.NET Core会自动为其添加隐式的[Required]验证规则。也就是说,哪怕你没手动加[BindRequired]或[Required],框架也会把这个参数当成必填项来校验,所以不传type的时候就会返回400错误。
你收到的错误日志也印证了这一点:
{ "errors": { "type": [ "The type field is required." ] }, "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1", "title": "One or more validation errors occurred.", "status": 400, "traceId": "|a516ca97-4f35ffd51f30acad." }
解决方案
这里有几种靠谱的解决方式,你可以根据自己的需求选择:
1. 将参数改为可空引用类型(推荐)
这是最符合Nullable设计意图的做法,直接把string type改成string? type,明确告诉框架这个参数是可选的:
[HttpPost("{imageId}/export", Name = nameof(ExportImage))] [ProducesResponseType(typeof(Business.Realhub.Models.User), StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status404NotFound)] [ProducesResponseType(StatusCodes.Status500InternalServerError)] public async Task<IActionResult> ExportImage( [FromRoute] int imageId, [FromQuery] string? type, // 改为可空类型 CancellationToken cancellationToken) { // 你的业务逻辑,注意处理type为null的情况 }
这样框架就不会再强制要求type参数必须存在了。
2. 全局禁用隐式必填验证
如果你不想在项目中使用这种自动验证行为,可以在Program.cs里配置关闭这个特性:
var builder = WebApplication.CreateBuilder(args); // 添加控制器服务时禁用隐式Required属性 builder.Services.AddControllers(options => { options.SuppressImplicitRequiredAttributeForNonNullableReferenceTypes = true; }); // 其他中间件配置...
这个配置会让框架不再自动给非可空引用类型参数添加[Required]验证,回到.NET 5及之前的行为。
3. 显式允许空字符串(如果需要)
如果你的场景是允许type参数存在但可以是空字符串(而不是完全不传),可以结合[Required(AllowEmptyStrings = true)],但这种情况还是建议配合可空类型一起使用,逻辑更清晰:
[FromQuery] [Required(AllowEmptyStrings = true)] string? type
总结
最推荐的方式是用可空引用类型(string?),既符合现代C#的编码规范,也能清晰表达参数的可选性。如果有全局的需求,再考虑修改框架的验证配置。
内容的提问来源于stack exchange,提问作者Carlo Luisito

