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

.NET 7 Web API接收POST集合参数始终为Null问题排查

问题分析与解决方案

核心原因

你遇到的问题源于**[FromForm]模型绑定对复杂列表类型的格式要求严格**,同时TimeOnly和DayOfWeek类型的表单绑定需要特定输入格式,前端提交的格式不匹配导致列表字段无法被正确解析。


解决方案

方案1:按表单数组格式提交(推荐,无需修改后端模型)

当使用[FromForm]接收带文件的请求时,前端必须用multipart/form-data格式提交,且列表字段需遵循索引式命名规则,具体操作如下:

  1. 前端构建FormData:
const formData = new FormData();
// 添加基础字段
formData.append('ServiceId', serviceId ?? '');
formData.append('UserId', userId);
formData.append('CategoryId', categoryId);
formData.append('Title', title);
formData.append('Description', description);
formData.append('Price', price);
// ...其他基础字段

// 处理Skills列表
skills.forEach((skill, index) => {
  formData.append(`Skills[${index}].SkillId`, skill.skillId ?? '');
  formData.append(`Skills[${index}].Name`, skill.name);
});

// 处理Availabilities列表(注意模型属性是DayOfWeeks,需严格对应)
availabilities.forEach((avail, index) => {
  // DayOfWeeks可传枚举值(如1=Monday)或枚举名称(如"Monday")
  formData.append(`Availabilities[${index}].DayOfWeeks`, avail.dayOfWeek);
  // TimeOnly必须传"HH:mm:ss"格式的字符串
  formData.append(`Availabilities[${index}].StartDate`, avail.startTime); // 例:"09:00:00"
  formData.append(`Availabilities[${index}].EndDate`, avail.endTime); // 例:"17:00:00"
});

// 添加文件
servicesImages.forEach(file => {
  formData.append('ServicesImages', file);
});

// 发送请求
await fetch('/api/services/upsert', {
  method: 'POST',
  body: formData
});
  1. 后端保持现有模型和控制器代码不变,ASP.NET Core的[FromForm]绑定器会自动解析这种格式的列表字段。

方案2:将列表序列化为JSON字符串提交(适合简化前端逻辑的场景)

如果不想处理表单索引命名,可以将列表转成JSON字符串作为单独表单字段提交,后端手动反序列化:

  1. 前端调整FormData构建:
const formData = new FormData();
// 添加基础字段...

// 将列表转为JSON字符串
formData.append('SkillsJson', JSON.stringify(skills));
formData.append('AvailabilitiesJson', JSON.stringify(availabilities));

// 添加文件...
  1. 后端创建DTO接收表单数据,再转换为原模型:
// 新增表单接收DTO
public class ServicesRequestFormDto
{
    public int? ServiceId { get; set; }
    public int UserId { get; set; }
    public int CategoryId { get; set; }
    public int? AddressId { get; set; }
    public int ServiceTypeId { get; set; }
    public string Title { get; set; }
    public string Description { get; set; }
    public decimal Price { get; set; }
    public string SkillsJson { get; set; }
    public string AvailabilitiesJson { get; set; }
    public IFormFileCollection ServicesImages { get; set; }
}

// 控制器修改
public async Task<ActionResult<ServicesResponse>> UpsertServicesAsync([FromForm] ServicesRequestFormDto formDto)
{
    // 反序列化列表字段
    var skills = JsonSerializer.Deserialize<List<SkillRequest>>(formDto.SkillsJson);
    var availabilities = JsonSerializer.Deserialize<List<AvailabilityRequest>>(formDto.AvailabilitiesJson);

    // 组装原业务模型
    var servicesRequest = new ServicesRequest
    {
        ServiceId = formDto.ServiceId,
        UserId = formDto.UserId,
        CategoryId = formDto.CategoryId,
        AddressId = formDto.AddressId,
        ServiceTypeId = formDto.ServiceTypeId,
        Title = formDto.Title,
        Description = formDto.Description,
        Price = formDto.Price,
        Skills = skills,
        Availabilities = availabilities,
        ServicesImages = formDto.ServicesImages
    };

    // 后续业务逻辑处理...
}

额外注意事项

  • TimeOnly类型:表单提交必须传递HH:mm:ss格式的字符串,不能直接传Date对象或其他格式。
  • DayOfWeek枚举:支持传递枚举名称(如"Monday")或对应整数值(如1),两种格式绑定器均可识别。
  • 属性名称一致性:前端表单字段名称必须和后端模型属性名称完全匹配(比如模型里是DayOfWeeks,前端不能写成DayOfWeek)。

内容的提问来源于stack exchange,提问作者Francisco Ojeda CL

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 14:50:54