[FromBody]绑定[BindNever]标记属性仍赋值如何解决
问题原因
[BindNever] 特性仅对MVC框架内置的表单、查询参数、路由参数等传统模型绑定源生效,标记该特性的属性不会被这些来源的值赋值。但当你使用[FromBody]接收JSON请求时,参数绑定的第一步是JSON序列化器(.NET Core 3.0+默认是System.Text.Json,部分项目会用Newtonsoft.Json)独立完成反序列化,这个流程不会识别MVC专属的[BindNever]标记,只要属性存在public的set访问器,JSON里携带的对应字段值就会被正常赋值给属性,这就是你拿到的X值是9而不是默认值0的核心原因。
解决方案
根据实际场景选以下任意一种即可:
- 方案1:给属性加JSON序列化忽略标记(最精准适配FromBody场景)
针对项目使用的JSON序列化器,在X属性上追加对应的忽略特性,让反序列化阶段直接跳过该属性:
如果使用默认的System.Text.Json:
如果项目配置使用Newtonsoft.Json做JSON序列化,把上面的using System.ComponentModel.DataAnnotations; using Microsoft.AspNetCore.Mvc; using System.Text.Json.Serialization; public class MyDto { [Required] public string Name { get; set; } [BindNever] // 覆盖非FromBody的表单、查询、路由等绑定场景 [JsonIgnore(Condition = JsonIgnoreCondition.Always)] // 反序列化、序列化时都完全忽略该属性 public int X { get; set; } }[JsonIgnore]替换为[Newtonsoft.Json.JsonIgnore]即可。 - 方案2:修改属性访问器权限(最省事,适合属性完全由服务端赋值的场景)
只要把X属性的set访问器改为非public,不管是传统模型绑定还是JSON反序列化,默认配置下都无法从外部请求给这个属性赋值:
后续服务端逻辑依然可以在类内部给X属性赋值,完全满足业务需求。注意不要用public class MyDto { [Required] public string Name { get; set; } public int X { get; private set; } // set改为私有,仅类内部可赋值 }init访问器,JSON反序列化器默认支持给init属性赋值,无法达到阻止绑定的效果。 - 方案3:全局配置模型绑定规则(适合需要批量统一管控绑定规则的场景)
如果不想在属性上加序列化相关的特性,可以在Program.cs的服务配置阶段,添加模型元数据规则,强制指定对应属性在所有绑定场景下都忽略:
这个配置会同时覆盖传统模型绑定和FromBody的反序列化绑定流程,不需要额外修改DTO类的代码。var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllers(options => { // 配置MyDto的X属性在所有模型绑定场景下都不接收请求值 options.ModelMetadataDetailsProviders.Add( new BindingSourceMetadataProvider( typeof(MyDto).GetProperty(nameof(MyDto.X)), BindingSource.Special ) ); });
补充说明:你贴出的请求体JSON存在语法错误("9后缺少闭合引号、对象缺少闭合大括号),但这个语法问题不会影响核心绑定逻辑的表现,修正语法后问题依然会存在。
内容的提问来源于stack exchange,提问作者Yoda
相关产品推荐
相关产品推荐

