Angular传FormData至.NET+MediatR时componentsData/cablesData映射为空
Angular应用通过FormData提交数据,包含tePartNumber、customerPN等普通字段,以及多条componentsData、cablesData条目(请求数据如下)。.NET端使用MediatR接收,定义了SaveDrawingDataCommand类,其中包含List<ComponentsDataDto>类型的componentsData和List<CablesDataDto>类型的cablesData,但接收时这两个列表始终为空,其他字段可正常获取。
请求打印数据:
Key: tePartNumber, Value: test
Key: customerPN, Value: test
Key: projectNumber, Value: test
Key: oem, Value: 994f433e-f36b-1410-9006-00a33fe338d1
Key: harnessMaker, Value: e14f433e-f36b-1410-9006-00a33fe338d1
Key: numberOfConnectors, Value: 2
Key: cdPath, Value: [object File]
Key: pdPath, Value: [object File]
Key: excelFilePath, Value: null
Key: imagePath, Value: [object File]
Key: componentsData, Value: {"componentId":"e94f433e-f36b-1410-9006-00a33fe338d1","side":"left"}
Key: componentsData, Value: {"componentId":"e94f433e-f36b-1410-9006-00a33fe338d1","side":"right"}
Key: cablesData, Value: {"componentId":"dd4f433e-f36b-1410-9006-00a33fe338d1"}
.NET端相关代码:
控制器方法:
[HttpPost] public async Task<ActionResult<RequestResponseMessage>> SaveDrawingData([FromForm] SaveDrawingDataCommand command) { try { Console.WriteLine("Compoentdata :"+ command.componentsData.Count); var response = await Mediator.Send(command); return Ok(response); } catch (Exception ex) { _logger.LogError(ex, "An error occurred while saving the drawing data."); return StatusCode(StatusCodes.Status500InternalServerError, ex.Message); } }
SaveDrawingDataCommand类:
public class SaveDrawingDataCommand : IRequest<SaveDrawingDataResponse> { public Guid Id { get; set;} public string? tePartNumber { get; set; } public string? customerPN { get; set; } public string? projectNumber { get; set; } public string? oem { get; set; } public string? harnessMaker { get; set; } public int numberOfConnectors { get; set; } public List<ComponentsDataDto>? componentsData { get; set; } public List<CablesDataDto>? cablesData { get; set; } public IFormFile? cdPath { get; set; } public IFormFile? pdPath { get; set; } public IFormFile? excelFilePath { get; set; } public IFormFile? imagePath { get; set; } }
ASP.NET Core的表单数据绑定机制,无法直接识别多个同名key对应单个JSON对象的格式为List<T>类型。当前请求中componentsData和cablesData是重复key,每个key对应一个独立的JSON对象,默认绑定逻辑不会将这些对象合并为列表。
方案1:Angular端将列表序列化为单个JSON字符串提交
修改Angular中FormData的构造逻辑,把整个componentsData和cablesData数组序列化为JSON字符串,作为单个key的值提交:
// 假设componentsData是你的数组变量 formData.append('componentsData', JSON.stringify(componentsData)); // cablesData同理 formData.append('cablesData', JSON.stringify(cablesData));
.NET端无需修改现有SaveDrawingDataCommand类,ASP.NET Core会自动将JSON字符串反序列化为List<ComponentsDataDto>和List<CablesDataDto>。
方案2:Angular端使用索引式表单字段命名
按照ASP.NET Core表单绑定的列表格式要求,使用索引标识每个列表项的属性:
componentsData.forEach((item, index) => { formData.append(`componentsData[${index}].componentId`, item.componentId); formData.append(`componentsData[${index}].side`, item.side); }); cablesData.forEach((item, index) => { formData.append(`cablesData[${index}].componentId`, item.componentId); });
这种方式符合默认表单绑定规则,.NET端无需修改代码即可正确映射为列表。
额外检查项
- 确保
ComponentsDataDto和CablesDataDto的属性名称与JSON字段完全匹配(ASP.NET Core默认大小写不敏感,但建议保持一致避免意外); - 确认Dto类的属性是公开可访问的(public),且包含对应的get/set方法。
- 修改Angular端代码后,重新提交请求,打印FormData的key-value,确保列表数据格式符合上述方案要求;
- 在.NET控制器中打印
command.componentsData.Count,检查是否已正确获取到列表长度; - 调试Handler方法,确认列表中的数据项已正确映射。
内容的提问来源于stack exchange,提问作者Chabba Mohamed Nadir

