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.
source to share
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();
}
source to share
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
source to share
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!
source to share