ASP.NET Core 2 MVC含MetadataPropertyHandling的JSON模型绑定问题
嘿,我来帮你搞定这个模型绑定的问题!你遇到的核心问题其实是两个:$type类型提示没起作用,以及加了[FromBody]后模型直接变null。咱们一步步拆解:
为什么$type不生效?
你JSON里的$type是JSON.NET(Newtonsoft.Json)的专属类型元数据,用来告诉序列化器该把JSON转成哪个具体类,但ASP.NET Core 2.x默认根本没开这个功能——毕竟随便允许类型反序列化有安全风险。另外你第二个JSON格式完全错了,$Values是给集合/数组用的,你的ApplicationLoggingModel是单个对象,完全没必要加这个结构。
为啥加[FromBody]后模型变null?
用[FromBody]时,ASP.NET Core会从请求体的原始JSON里绑定模型,但如果JSON格式不对、序列化配置不匹配,就会出现模型为null的情况。你第一个JSON里的$type其实干扰了默认绑定逻辑,因为默认序列化器(虽然2.x用的是JSON.NET,但默认没开启类型名称处理)不认这个额外字段,直接导致绑定失败。
两种解决方案,看你需求选:
方案一:去掉$type(推荐,简单直接)
如果你的接口本来就只接收ApplicationLoggingModel类型,完全没必要传$type,把JSON简化成这样就行:
{ "Test": "works" }
控制器代码保持不变(必须保留[FromBody]),这样模型绑定就能正常工作了——默认序列化器会直接把JSON转成指定的模型类,不需要额外的类型提示。
方案二:必须用$type(比如多态场景)
要是因为多态之类的原因必须传$type,那得改ASP.NET Core的JSON序列化配置,开启类型名称处理:
- 打开
Startup.cs,在ConfigureServices方法里添加JSON.NET的配置:
using Newtonsoft.Json; using Newtonsoft.Json.Serialization; public void ConfigureServices(IServiceCollection services) { services.AddMvc() .AddNewtonsoftJson(options => { // 开启类型名称处理,让序列化器识别$type字段 options.SerializerSettings.TypeNameHandling = TypeNameHandling.Objects; // 可选:如果你的JSON字段大小写和模型不匹配,可以加这个驼峰命名解析器 options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); }); }
- 修正JSON里的
$type值,必须完全匹配类的完整限定名+程序集名称:
{ "$type": "Namespace.Models.ApplicationLoggingModel, Projectname.Web", "Test": "works" }
注意哦!你之前写的Namespace.ApplicationLoggingModel少了Models命名空间,这也是绑定失败的一个关键原因!
- 控制器代码不用改,
[FromBody]必须留着,因为要从请求体读取JSON:
[HttpPost("Save/{id}")] public ActionResult Save(Guid id, [FromBody]ApplicationLoggingModel model) { return RedirectToAction("Entities", Guid.Empty); }
最后提醒几个小细节
- 别乱用
$Values,那是给数组、List这类集合用的,单个对象完全不需要。 - 开启
TypeNameHandling后要注意安全,只在可信的客户端用,避免被恶意类型攻击。 - 检查请求的
Content-Type是不是application/json,要是传成application/x-www-form-urlencoded这类,[FromBody]也会绑定失败。
内容的提问来源于stack exchange,提问作者James Morrison

