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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 09:04:02