ASP.NET Core 2与Angular 5中如何通过[FromBody]接收文件
问题根源分析
你现在遇到的核心问题是:JSON格式无法传输二进制文件,而你当前用HttpClient.post把Organization对象以JSON形式发送到服务器,ASP.NET Core的[FromBody]只能解析JSON数据,但IFormFile对应的是二进制文件内容,无法通过JSON序列化/反序列化处理,这就是带文件时orgDto为null的原因。
下面是完整的解决方案,分Angular端和ASP.NET Core端两部分修改:
一、Angular端修改:改用FormData传输文件
1. 组件内保存原始文件对象
先在organization-form.component.ts里新增变量存储选中的原始文件,同时修改预览方法:
selectedFile: File; localImg: string; showPreviewImage(event: any) { if (event.target.files && event.target.files[0]) { // 保存原始文件对象(关键:不要用base64,要用File实例) this.selectedFile = event.target.files[0]; const reader = new FileReader(); reader.readAsDataURL(this.selectedFile); reader.onload = () => { this.localImg = reader.result as string; // 用文件名填充logoUrl字段 this.editForm.patchValue({ logoUrl: this.selectedFile.name }); this.editForm.markAsDirty(); } } }
2. 构建FormData替代JSON提交
修改save方法,把表单数据和文件封装成FormData:
save() { const formData = new FormData(); // 逐个添加普通表单字段 formData.append('id', this.editForm.get('id').value); formData.append('organizationName', this.editForm.get('organizationName').value); formData.append('legalName', this.editForm.get('legalName').value); formData.append('logoUrl', this.editForm.get('logoUrl').value); // 添加文件(如果有选中) if (this.selectedFile) { formData.append('logoFile', this.selectedFile, this.selectedFile.name); } this.onSubmit.emit(formData); }
3. 修改HttpClient请求配置
调整create方法,直接发送FormData,不要手动设置Content-Type(让浏览器自动添加multipart/form-data及boundary标识):
create(formData: FormData) { return this.httpClient.post(this.baseUrl + 'organization/create', formData, { headers: new HttpHeaders({ // 注释掉手动设置的Content-Type,避免缺失boundary // 'Content-Type': 'multipart/form-data' }) }); }
二、ASP.NET Core端修改:接收FormData
1. 调整控制器参数绑定
把[FromBody]改成[FromForm],因为现在是表单数据提交:
[HttpPost("create")] public async Task<IActionResult> CreateOrganization([FromForm] OrganizationDto orgDto) { // 检查组织名称是否重复 if (await _orgRepo.OrganizationExist(orgDto.OrganizationName)) { ModelState.AddModelError("OrganizationName", "Organization Name already exists"); } if (!ModelState.IsValid) return BadRequest(ModelState); var orgToCreate = _mapper.Map<Organization>(orgDto); if(orgDto.LogoFile != null) { // 确保存储目录存在,避免报错 if (!Directory.Exists(this.logosFolderPath)) { Directory.CreateDirectory(this.logosFolderPath); } var filePath = Path.Combine(this.logosFolderPath, orgDto.LogoFile.FileName); using (var stream = new FileStream(filePath, FileMode.Create)) { await orgDto.LogoFile.CopyToAsync(stream); } orgToCreate.LogoUrl = orgDto.LogoFile.FileName; } var createdOrg = await _orgRepo.CreateOrganization(orgToCreate); var orgToReturn = _mapper.Map<OrganizationDetailedDto>(createdOrg); return Ok(orgToReturn); }
2. 可选:优化DTO验证逻辑
如果LogoUrl是用来存储文件名,建议去掉它的[Required]特性,因为上传文件后可以直接用LogoFile.FileName赋值,避免前端还要维护hidden字段的验证。
关键注意点
- JSON不支持二进制数据,文件必须通过
multipart/form-data格式传输,这是浏览器上传文件的标准方式。 - ASP.NET Core中,
[FromBody]用于解析JSON,[FromForm]用于解析表单数据,两者不能混用。 - 不要手动设置
multipart/form-data的Content-Type,否则会缺失自动生成的boundary标识,导致服务器无法正确解析文件。
内容的提问来源于stack exchange,提问作者nightingale2k1
相关产品推荐
相关产品推荐

