使用 Asp.Net Core Web API 文件上传文件始终为空

Posted

技术标签:

【中文标题】使用 Asp.Net Core Web API 文件上传文件始终为空【英文标题】:File upload using Asp.Net Core Web API file is always null 【发布时间】:2017-10-21 05:03:08 【问题描述】:

我正在使用 Angular 2 和 ASP.NET 核心 Web API 来实现文件上传来处理请求。

我的 html 代码如下所示:

<input #fileInput type="file"/>
<button (click)="addFile()">Add</button>

还有angular2代码

addFile(): void 
    let fi = this.fileInput.nativeElement;
    if (fi.files && fi.files[0]) 
        let fileToUpload = fi.files[0];
        this.documentService
            .uploadFile(fileToUpload)
            .subscribe(res => 
                console.log(res);
        );
    

服务看起来像

public uploadFile(file: any): Observable<any> 
    let input = new FormData();
    input.append("file", file, file.name);
    let headers = new Headers();
    headers.append('Content-Type', 'multipart/form-data');
    let options = new RequestOptions( headers: headers );
    return this.http.post(`/api/document/Upload`, input, options);

和控制器代码

[HttpPost]
public async Task Upload(IFormFile file)

    if (file == null) throw new Exception("File is null");
    if (file.Length == 0) throw new Exception("File is empty");

    using (Stream stream = file.OpenReadStream())
    
        using (var binaryReader = new BinaryReader(stream))
        
            var fileContent = binaryReader.ReadBytes((int)file.Length);
            //await this.UploadFile(file.ContentDisposition);
        
    

我的 RequestHeader 看起来像

POST /shell/api/document/Upload HTTP/1.1
Host: localhost:10050
Connection: keep-alive
Content-Length: 2
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJDb3JyZWxhdGlvbklkIjoiZDZlNzE0OTUtZTM2MS00YTkxLWExNWUtNTc5ODY5NjhjNDkxIiwiVXNlcklkIjoiMSIsIlVzZXJOYW1lIjoiWjk5OTkiLCJXb3Jrc3BhY2UiOiJRc3lzVFRAU09BVEVNUCIsIk1hbmRhbnRJZCI6IjUwMDEiLCJDb3N0Q2VudGVySWQiOiIxMDAxIiwiTGFuZ3VhZ2VDb2RlIjoiMSIsIkxhbmd1YWdlU3RyaW5nIjoiZGUtREUiLCJTdGF0aW9uSWQiOiI1NTAwMSIsIk5hbWUiOiJJQlMtU0VSVklDRSIsImlzcyI6InNlbGYiLCJhdWQiOiJodHRwOi8vd3d3LmV4YW1wbGUuY29tIiwiZXhwIjoxNDk1Mzc4Nzg4LCJuYmYiOjE0OTUzNzUxODh9.5ZP7YkEJ2GcWX9ce-kLaWJ79P4d2iCgePKLqMaCe-4A
Origin: http://localhost:10050
User-Agent: Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36
Content-Type: multipart/form-data
Accept: application/json, text/plain, */*
Referer: http://localhost:10050/fmea/1064001/content
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.8

我面临的问题是控制器中的文件始终为空。

请有人帮我解决问题。

提前致谢。

【问题讨论】:

您是否尝试将控制器方法更改为公共异步任务上传(ICollection 文件) 但是我在@Dipak 服务中只传递了一个文件 我还怀疑您将集合发布为 FormData。所以换成 List 试试吧! 我试过了,没用。我是否必须在控制器中设置任何内容才能接受 mulitpart/form-data? 您能从Upload 操作中检查Request.Form.Files 控制器属性吗? 【参考方案1】:

您不需要将“multipart/form-data”与 FormData 一起使用

在 Angular 2 组件中:

<input type="file" class="form-control" name="documents" (change)="onFileChange($event)" />

onFileChange(event: any) 
    let fi = event.srcElement;
    if (fi.files && fi.files[0]) 
        let fileToUpload = fi.files[0];

        let formData:FormData = new FormData();
         formData.append(fileToUpload.name, fileToUpload);

        let headers = new Headers();
        headers.append('Accept', 'application/json');
        // DON'T SET THE Content-Type to multipart/form-data, You'll get the Missing content-type boundary error
        let options = new RequestOptions( headers: headers );

        this.http.post(this.baseUrl + "upload/", formData, options)
                 .subscribe(r => console.log(r));
    

在 API 方面

[HttpPost("upload")]
public async Task<IActionResult> Upload()

    var files = Request.Form.Files;

    foreach (var file in files)
    
       // to do save
    

    return Ok();

【讨论】:

如果我不使用 IFormFile 那么 Request.Form.Files 是空的。我正在使用 Angular 7 和 .netcore 2.1 Request.Form.Files 是救命稻草! [FromForm] 没有帮助【参考方案2】:

使用 dotnet core 的另一种方式,您可以使用 IFormFile 接口,并设置默认标题:

Angular 2

 let formData = new FormData();
 formData.append("file", yourUploadFile);

 this.http.post("your_api_path", formData).subscribe(r => console.log(r));

Dotnet 核心

 [HttpPost]
 [Route("/your_api_path")]
 public async Task<IActionResult> Upload(IFormFile file) 
     //...next awaiters...    

如果要发送多个文件,可以使用ICollection&lt;IFormFile&gt; 作为上传参数。

要发送多个属性,您可以使用自定义模型对象,而 IFormFile 将是属性之一。

希望对您有所帮助!

【讨论】:

这不起作用。使用 Angular 7 和 .NET Core 2.1.1【参考方案3】:

更新: 经过 ASP.NET Core 团队的一些澄清后,它与 Startup 类中的兼容开关有关。如果你这样设置:

services
    .AddMvc()
    .SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

如果你也从文件参数中删除[FromForm] 属性就可以了。

旧帖: 我在使用最新的 ASP.NET Core WebApi(发布本文时为 2.1.2)时遇到了一个类似的问题,经过一个小时的 ***、研究和大量试验和错误,我只能偶然解决这个问题。我从 Angular 6 应用程序中发布文件,如下所示:

const formData: FormData = new FormData();
formData.append('file', file, file.name);

const req = new HttpRequest('POST', 'upload-url', formData, 
    reportProgress: true
);

this.http.request(req).subscribe(...) // omitted the rest

问题在于,IFormFile file Action 方法参数始终为 null,即使将 [FromForm] 放在它前面也是如此。由于 ASP.NET Core 2.1 中的 api 控制器行为发生变化,[FromForm] 是必需的,其中[FromBody] 成为 api 控制器的默认值。奇怪的是还是不行,值一直是null

我终于通过使用属性显式声明表单内容参数的名称来解决它,像这样:

public async Task<IActionResult> UploadLogo([FromForm(Name = "file")] IFormFile file)        

     ...

现在文件上传已正确绑定到控制器参数。我希望这可能会在未来对某人有所帮助,因为它几乎让我失去理智:D

【讨论】:

我不太关注'[FromForm(Name = "file")]'? “文件”指的是什么?我正在尝试将带有几个字符串的 ViewModel 和一个 File 从 Angular 传递到 ASP.NET Core,并且字符串可以正常传递,但 File 始终为空。有什么想法吗? @RuneStar “文件”是指发布的表单数据中文件数据的标识符。因为它附加在代码的 Angular 部分中。关于您的 ViewModel 问题,我认为以下答案具有正确的想法,因为您可能需要为此自定义模型绑定。 我遇到的问题是,当我在“文件”输入中添加“formControlName”或“[formControl]”指令时,表单不喜欢它。不知道为什么,但摆脱了它,我可以将图像上传到控制器动作就好了。 就您的回复而言,我很好奇,这是否意味着我可以对任意数量的各种“FormData”标识符中的每一个进行单独的操作,并且它们都会在每个 POST 时被调用?例如,如果您添加了 'formData.append('anotherFile', file, file.anotherName)' 我可以创建一个操作 'public async Task UploadOtherLogo([FromForm(Name = "anotherFile")] IFormFile anotherFile)' ? 我想是的。是的:)【参考方案4】:

核心 3.1

[HttpPost("upload-bulk-excel"), DisableRequestSizeLimit]
public IActionResult Upload()

  try
  
    var file = Request.Form.Files[0];

Angular 8

uploadExcelFile() 
  const formData = new FormData();
  formData.append('file', this.fileToUpload, this.fileToUpload.name);

  this._httpClient.post(`$environment.apiUrl/upload/upload-bulk-excel`, formData, reportProgress: true, observe: 'events')
    .subscribe(event => 
      if (event.type === HttpEventType.UploadProgress)
        this.uploadProgress = Math.round(100 * event.loaded / event.total);
      else if (event.type === HttpEventType.Response) 
        this.uploadMessage = 'Upload success.';
      alert('File uploaded successfully');
    
  );

【讨论】:

以上是关于使用 Asp.Net Core Web API 文件上传文件始终为空的主要内容,如果未能解决你的问题,请参考以下文章

使用 ASP.NET Core MVC 创建 Web API

使用 ASP.NET Core MVC 创建 Web API

Asp.Net Core 1.1 消费web api

使用 ASP.NET Core MVC 创建 Web API

ASP.NET Core 实战:使用 ASP.NET Core Web API 和 Vue.js 搭建前后端分离项目

ASP.NET Core Web API