File upload using Asp.Net web API file is always zero

I am doing a file upload using Angular 2 using ASP.NET Web API to handle a request.

My html code looks like this:

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

      

and angular2 code

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);
        });
    }
}

      

and the service looks like

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);
}

      

and controller code

[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);
        }
    }
}

      

My RequestHeader looks like

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

      

The problem I'm running into is that the file is always null in the controller.

Please help me figure out the problem.

Thanks in advance.

+6


source to share


3 answers


You don't need to use "multipart / form-data" with FormData p>

In Angular 2 the components:

<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 side

[HttpPost("upload")]
public async Task<IActionResult> Upload()
{
    var files = Request.Form.Files;

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

    return Ok();
}

      

+15


source


Update: After some clarification from the ASP.NET Core Team, this is related to the compat switch in the class Startup

. If you install it like this:

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

      

then it's ok if you also remove the attribute [FromForm]

from the file parameter.

Old post: I ran into a similar issue with the latest version of ASP.NET Core WebApi (2.1.2 at the time of this writing) that I could only solve by accident after an hour, research, and a lot of trial and error. I was posting a file from Angular 6 app like this:

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

      



The problem was that the action method parameter IFormFile file

was always there null

, even if placed [FromForm]

in front of it. [FromForm]

was required due to changes in API controller behavior in ASP.NET Core 2.1, where [FromBody]

it becomes the default for API controllers. Oddly enough, it still didn't work, the value remained null

.

I finally solved this issue by explicitly specifying the name of the form content parameter using an attribute, like so:

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

      

The file upload was now correctly bound to the controller parameter. I hope this can help someone in the future, as it almost cost me my sanity: D

+6


source


Another way with dotnet core is to use the IFormFile interface with the default headers setting:

Angular 2

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

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

      

Dotnet Core

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

      

If you want to send multiple files, you can use ICollection<IFormFile>

as upload parameters.

You can use a custom model object to send multiple properties, and the IFormFile will be one of the properties.

Hope this helps!

+3


source







All Articles