.NET Core 8中[FromForm]无法接收JSON格式值的问题
.NET版本升级后Form表单中JSON格式字段解析异常问题
原本正常运行的.NET Core API,接收3个核心参数(Key、Message、Topic)及可选Headers,旧版本中Message字段可同时接收JSON、XML格式字符串并正常解析。升级至最新.NET版本后出现以下问题:
- 当向Message字段传递标准JSON格式值(如
{"Name":"Nikhil"})时,API返回400错误,提示Message字段不能为空 - 查看生成的curl请求发现,标准JSON中的键被识别为独立的表单字段(比如
Name=Nikhil被单独作为一个表单项),导致原Message字段缺失 - 传递非标准JSON格式(如
{"Name"="Nikhil"})时,请求可正常执行
控制器及模型代码未做改动,具体代码如下:
控制器代码
[HttpPost("Produce/v2")] public async Task<IActionResult> ProduceForm([FromForm] KafkaPublisherRequest kafkaPublisherRequest) { if (kafkaPublisherRequest == null || !ModelState.IsValid) { return BadRequest(); } _logger.LogInformation($"Started Publishing into Kafka Topic : {kafkaPublisherRequest.Topic}, Key :{kafkaPublisherRequest.Key}"); // 核心业务代码 return Ok(new ServiceResult(ServiceState.Completed, kafkaPublisherRequest.Key, "Produced Successfully")); }
模型类代码
public class KafkaPublisherRequest { [Required] public string Key { get; set; } [Required] public string Message { get; set; } [Required] public string Topic { get; set; } public Dictionary<string, string> Headers { get; set; } }
异常请求的curl示例
curl -X 'POST' \ 'https://localhost:5001/xxxxx' \ -H 'accept: text/plain' \ -H 'Content-Type: multipart/form-data' \ -F 'Key=Key' \ -F 'Name=Nikhil' \ -F 'Topic=topic' \ -F 'Headers=' \ -F 'Headers='
正常请求的curl示例
curl -X 'POST' \ 'https://localhost:5001/api/KafkaProducer/Produce/v2' \ -H 'accept: text/plain' \ -H 'Content-Type: multipart/form-data' \ -F 'Key=Key' \ -F 'Message={"Name"="Nikhil"}' \ -F 'Topic=sdajsdasd' \ -F 'Headers='
解决方案
原因分析
最新.NET版本中,multipart/form-data解析器对包含:的表单值处理逻辑发生变化,将标准JSON中的键值对误识别为独立表单字段,导致原Message字段未被正确绑定。
解决方法
方法1:对JSON字符串进行URL编码
在发送请求时,将Message字段的标准JSON值进行URL编码,避免解析器误拆分。例如:
curl -X 'POST' \ 'https://localhost:5001/api/KafkaProducer/Produce/v2' \ -H 'accept: text/plain' \ -H 'Content-Type: multipart/form-data' \ -F 'Key=Key' \ -F 'Message=%7B%22Name%22%3A%22Nikhil%22%7D' \ -F 'Topic=sdajsdasd' \ -F 'Headers='
({"Name":"Nikhil"}的URL编码结果为%7B%22Name%22%3A%22Nikhil%22%7D)
方法2:修改API接收方式,使用[FromBody]替代[FromForm]
如果允许客户端发送application/json格式请求,可修改控制器方法的参数绑定方式:
[HttpPost("Produce/v2")] public async Task<IActionResult> ProduceForm([FromBody] KafkaPublisherRequest kafkaPublisherRequest) { // 原有逻辑不变 }
客户端请求需改为发送JSON体:
curl -X 'POST' \ 'https://localhost:5001/api/KafkaProducer/Produce/v2' \ -H 'accept: text/plain' \ -H 'Content-Type: application/json' \ -d '{ "Key": "Key", "Message": "{\"Name\":\"Nikhil\"}", "Topic": "sdajsdasd", "Headers": {} }'
方法3:自定义表单绑定器
如果必须保留multipart/form-data方式,可自定义绑定逻辑确保Message字段被正确解析:
- 创建自定义模型绑定器:
public class JsonStringModelBinder : IModelBinder { public Task BindModelAsync(ModelBindingContext bindingContext) { if (bindingContext == null) throw new ArgumentNullException(nameof(bindingContext)); var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName); if (valueProviderResult == ValueProviderResult.None) return Task.CompletedTask; bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult); var value = valueProviderResult.FirstValue; // 直接将值作为字符串返回,避免解析拆分 bindingContext.Result = ModelBindingResult.Success(value); return Task.CompletedTask; } }
- 在模型类的Message字段上应用绑定器:
[Required] [ModelBinder(BinderType = typeof(JsonStringModelBinder))] public string Message { get; set; }
内容的提问来源于stack exchange,提问作者Nikhil Srivastava
相关产品推荐
相关产品推荐

