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

如何从Angular向.NET Web API上传文件及数组类型数据

解决Angular FormData嵌套数组在.NET Core Web API中无法获取的问题

问题根源

直接将FormArray的值通过formData.append('Items', this.InvoiceForm.get('InvoiceItem').value)添加到FormData时,浏览器会将数组对象转换为无意义的字符串(通常是[object Object]),导致后端无法解析为有效的数组结构。


方案一:将数组序列化为JSON字符串传输(简单直接)

前端修改

调整Save方法,把InvoiceItem数组转为JSON字符串后再添加到FormData:

Save() {
  const formData = new FormData();
  formData.append('file', this.selectedFile, this.selectedFile.name);
  formData.append('Discription', this.InvoiceForm.get('Discription').value);
  formData.append('Date', this.InvoiceForm.get('EntryDate').value);
  // 将数组序列化为JSON字符串
  formData.append('Items', JSON.stringify(this.InvoiceForm.get('InvoiceItem').value));

  // 移除手动设置的enctype,HttpClient会自动处理multipart/form-data的boundary
  this._http.post(environment.Item, formData).subscribe(
    res => console.log('提交成功'),
    err => console.error('提交失败', err)
  );
}

后端修改

  1. 创建数据传输对象(DTO):
public class InvoiceItemDto
{
    public string ItemName { get; set; }
    public string ItemType { get; set; }
    public string Quantity { get; set; }
    public string Unit { get; set; }
    public string Category { get; set; }
    public string Depo { get; set; }
    public string Comments { get; set; }
}

public class InvoiceRequestDto
{
    public IFormFile File { get; set; }
    public string Discription { get; set; }
    public string Date { get; set; }
    public string Items { get; set; } // 存储JSON字符串
}
  1. 修改API接口,反序列化JSON字符串为对象数组:
using System.Text.Json;

[HttpPost, DisableRequestSizeLimit]
public async Task<ActionResult> AddItem([FromForm] InvoiceRequestDto request)
{
    var file = request.File;
    var description = request.Discription;
    var date = request.Date;
    
    // 反序列化JSON字符串为InvoiceItemDto数组
    var items = JsonSerializer.Deserialize<List<InvoiceItemDto>>(request.Items);
    
    // 这里添加你的业务逻辑,比如保存文件、存储数据等
    return Ok();
}

方案二:按表单字段格式逐个添加数组元素(符合form-data规范)

前端修改

通过循环将数组中的每个对象的属性按Items[index].key的格式添加到FormData:

Save() {
  const formData = new FormData();
  formData.append('file', this.selectedFile, this.selectedFile.name);
  formData.append('Discription', this.InvoiceForm.get('Discription').value);
  formData.append('Date', this.InvoiceForm.get('EntryDate').value);

  // 遍历InvoiceItem数组,逐个添加属性
  const items = this.InvoiceForm.get('InvoiceItem').value as any[];
  items.forEach((item, index) => {
    // 遍历每个item的属性
    Object.keys(item).forEach(key => {
      // 空值跳过,避免传递无效数据
      if (item[key] !== null && item[key] !== undefined) {
        formData.append(`Items[${index}].${key}`, item[key]);
      }
    });
  });

  this._http.post(environment.Item, formData).subscribe(
    res => console.log('提交成功'),
    err => console.error('提交失败', err)
  );
}

后端修改

  1. 调整InvoiceRequestDto,直接使用数组类型:
public class InvoiceRequestDto
{
    public IFormFile File { get; set; }
    public string Discription { get; set; }
    public string Date { get; set; }
    public List<InvoiceItemDto> Items { get; set; } // 直接接收数组
}
  1. API接口无需手动反序列化,模型绑定会自动处理:
[HttpPost, DisableRequestSizeLimit]
public async Task<ActionResult> AddItem([FromForm] InvoiceRequestDto request)
{
    var file = request.File;
    var description = request.Discription;
    var date = request.Date;
    var items = request.Items; // 直接获取解析后的数组
    
    // 业务逻辑处理
    return Ok();
}

注意事项

  • 移除Angular请求中手动设置的enctype:HttpClient在传输FormData时会自动生成包含boundary的Content-Type头,手动设置会丢失boundary导致后端解析失败。
  • 确保DTO的属性名称与前端FormData中的键名完全一致(区分大小写,比如前端的Discription和后端的Discription要一致)。
  • 若使用方案二,空值属性建议跳过添加,避免传递无效的空字符串或null值。

内容的提问来源于stack exchange,提问作者Mehrab Shaida

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 00:35:30