File upload using Asp.Net Core Web API file is always null

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

In Angular 2 component:

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

On API side

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

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

    return Ok();
}

Update: After some clarification from the ASP.NET Core Team, it has to do with the compat switch in the Startup class. If you set it like this:

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

then you are fine if you also remove the [FromForm] Attribute from the file parameter.

Old Post: I ran into a similiar problem with the latest ASP.NET Core WebApi (2.1.2 at the time of this post), which I could only solve by accident after an hour of stackoverflowing, research and lots of trial and error. I was posting the file from an Angular 6 application 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 IFormFile file Action method parameter was always null even when putting [FromForm] in front it. The [FromForm] was necessary due to api controller behavior changes in ASP.NET Core 2.1, where [FromBody] becomes the default for api controllers. Strangely, it still didn't work, the value stayed null.

I finally solved it by explicitly stating the name of the form content parameter using the attribute, like this:

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

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


Another way with dotnet core, you can use IFormFile interface, with setting default headers:

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 send multiple files, you can use ICollection<IFormFile> as Upload params.

For sending multiple properties you can use custom model object and IFormFile will be one of properties.

Hope it help!