You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.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字段被正确解析:

  1. 创建自定义模型绑定器:
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;
    }
}
  1. 在模型类的Message字段上应用绑定器:
[Required]
[ModelBinder(BinderType = typeof(JsonStringModelBinder))]
public string Message { get; set; }

内容的提问来源于stack exchange,提问作者Nikhil Srivastava

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 15:40:21