.NET Core 5.0 JSON绑定简单参数失效 如何恢复ASP.NET MVC原有绑定逻辑
问题原因
ASP.NET Core 的模型绑定逻辑和 .NET Framework 版 ASP.NET MVC 存在核心差异:
- 默认
[FromBody]只能绑定一个参数,会把整个请求体的内容反序列化为该参数的类型,没法拆分JSON对象的多个字段分别绑定到多个简单参数上 - 没有加绑定特性的简单类型参数(比如string、int),默认只会从路由、查询字符串里取值,不会读取请求体内容
- 你之前Fiddler测试时存在格式错误:发送JSON格式的请求体时,
Content-Type必须设置为application/json,如果用application/x-www-form-urlencoded,请求体应该是firstname=foo&lastname=bar的键值对格式,传JSON串肯定绑定失败。
解决方案(无需修改原有方法签名)
可以通过自定义全局模型绑定器恢复旧版的绑定逻辑,操作步骤如下:
- 实现自定义绑定器和绑定提供者:
using Microsoft.AspNetCore.Mvc.ModelBinding; // 如果你用默认System.Text.Json,替换下面Newtonsoft.Json的相关代码即可 using Newtonsoft.Json.Linq; public class SimpleTypeFromJsonBinder : IModelBinder { public async Task BindModelAsync(ModelBindingContext bindingContext) { if (bindingContext == null) throw new ArgumentNullException(nameof(bindingContext)); // 仅处理简单类型参数 if (!bindingContext.ModelType.IsPrimitive && bindingContext.ModelType != typeof(string)) return; var request = bindingContext.HttpContext.Request; if (!request.ContentType.Contains("application/json")) return; // 允许请求体重复读取,适配多参数绑定场景 request.EnableBuffering(); using var reader = new StreamReader(request.Body, leaveOpen: true); var bodyContent = await reader.ReadToEndAsync(); request.Body.Position = 0; if (string.IsNullOrWhiteSpace(bodyContent)) return; try { var jsonObj = JObject.Parse(bodyContent); var targetValue = jsonObj[bindingContext.FieldName]?.ToString(); if (targetValue != null) { var convertedVal = Convert.ChangeType(targetValue, bindingContext.ModelType); bindingContext.Result = ModelBindingResult.Success(convertedVal); } } catch { // 解析异常时走默认绑定逻辑即可 } } } public class SimpleTypeFromJsonBinderProvider : IModelBinderProvider { public IModelBinder GetBinder(ModelBinderProviderContext context) { if (context == null) throw new ArgumentNullException(nameof(context)); if (context.Metadata.IsPrimitive || context.Metadata.ModelType == typeof(string)) { return new SimpleTypeFromJsonBinder(); } return null; } }
- 在
Startup.cs的ConfigureServices中注册绑定提供者,需要放到默认绑定提供者的最前面:
public void ConfigureServices(IServiceCollection services) { services.AddControllers(options => { options.ModelBinderProviders.Insert(0, new SimpleTypeFromJsonBinderProvider()); }); }
配置完成后,原有方法签名不需要做任何修改,就能直接从JSON请求体中绑定对应字段到简单参数上。
官方推荐替代方案
如果不想引入自定义绑定逻辑,也可以用C# 9+的记录类型简化请求类编写,代码量非常少:
// 一行定义请求模型 public record BlahRequest(string firstname, string lastname); // 仅需要修改方法签名为如下形式 public IActionResult Blah([FromBody] BlahRequest request) { // 直接使用 request.firstname、request.lastname 即可 }
这种方案性能比自定义绑定器更好,也不会有自定义逻辑可能带来的边界问题,是.NET Core官方推荐的最佳实践。
内容的提问来源于stack exchange,提问作者Josh
相关产品推荐
相关产品推荐

