向C#控制器传递复杂JS对象时列表始终为空的问题
我之前也碰到过一模一样的问题!这种情况大概率是序列化/反序列化的匹配问题,或者列表属性的绑定规则没搞对,给你列几个最常见的排查和解决方向:
C# 默认用 PascalCase(比如Products)命名属性,而 JavaScript 里习惯用 camelCase(比如products)。如果你的控制器模型里属性是:
public List<Product> Products { get; set; }
但 JS 请求里写的是products: productlist,ASP.NET 的默认序列化器可能匹配不上。解决方法二选一:
- 把 JS 请求里的属性名改成大写开头:
Products: productlist - 给 C# 属性加特性指定匹配的小写名称:
using System.Text.Json.Serialization; public class YourModel { // 其他属性... [JsonPropertyName("products")] public List<Product> Products { get; set; } }
就算外层列表传过去了,如果列表里每个Product对象的属性和 C# 的Product模型不对应,也可能导致整个列表被反序列化为空。比如 C# 里Product有ProductId字段,但 JS 里是id,那每个子对象绑定失败,最终列表就会是空的。
可以用浏览器的 Network 面板查看请求的 Raw 数据,把序列化后的 JSON 和 C# 模型逐一对比,确保每个字段名称、类型都对应。
[FromBody]特性 一定要确保你的控制器方法参数前面加了[FromBody],否则 ASP.NET 会默认用表单绑定,而不是 JSON 绑定,列表自然无法正确解析:
[HttpPost] public IActionResult Create([FromBody] YourModel model) { // 处理逻辑 }
在发送请求前,先把序列化后的字符串打出来看看:
const request = {Id: null, /* 其他属性 */, Products: productlist}; console.log(JSON.stringify(request));
有时候看起来productlist有数据,但可能是引用问题或者没正确赋值,序列化后其实是空数组。比如如果productlist是 DOM 元素集合,不是纯 JS 对象数组,那序列化后就会出问题,得先把 DOM 数据转成对应的 JS 对象。
C# 的模型类(包括YourModel和Product)必须有无参构造函数,否则反序列化器无法创建实例,可能导致列表为空。如果你的模型只有带参数的构造函数,记得补一个无参的:
public class YourModel { // 无参构造函数必须有 public YourModel() {} public int? Id { get; set; } public List<Product> Products { get; set; } // 其他属性 }
如果用的是 ASP.NET Core 3.0+,默认用的是System.Text.Json,它对某些格式的兼容性不如 Newtonsoft.Json。可以试试切换:
- 安装 NuGet 包:
Microsoft.AspNetCore.Mvc.NewtonsoftJson - 在
Program.cs里配置:builder.Services.AddControllers().AddNewtonsoftJson();
有时候换个序列化器就能解决这种奇怪的绑定问题。
内容的提问来源于stack exchange,提问作者user1167777

