如何从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) ); }
后端修改
- 创建数据传输对象(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字符串 }
- 修改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) ); }
后端修改
- 调整
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; } // 直接接收数组 }
- 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
相关产品推荐
相关产品推荐

