Reputation: 1377
I have asp.net core server (using .net core 2.2) that has FileUploadController which listens to post request for incoming file.
[HttpPost("Upload")]
// public async Task<IActionResult> Upload([FromForm(Name="file")]IFormFile file) {
// public async Task<IActionResult> Upload([FromForm]IFormFile file) {
public async Task<IActionResult> Upload(IFormFile file) {
Console.WriteLine("***" + file);
if(file == null) return BadRequest("NULL FILE");
if(file.Length == 0) return BadRequest("Empty File");
Console.WriteLine("***" + host.WebRootPath);
if (string.IsNullOrWhiteSpace(host.WebRootPath))
{
host.WebRootPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot");
}
var uploadsFolderPath = Path.Combine(host.WebRootPath, "uploads");
if (!Directory.Exists(uploadsFolderPath)) Directory.CreateDirectory(uploadsFolderPath);
var fileName = "Master" + Path.GetExtension(file.FileName);
var filePath = Path.Combine(uploadsFolderPath, fileName);
using (var stream = new FileStream(filePath, FileMode.Create))
{
await file.CopyToAsync(stream);
}
return Ok("Okay");
}
I have created angular app (using angular version 8) which can choose file to upload at ClientApplication and I have created three post service that called to the api "http://localhost:5000/api/fileupload/upload".
Standard Angular HttpClient Post. when server reads, the IFormFile is null.
const formData: FormData = new FormData();
formData.append('file', file, file.name);
// return this.http.post(this.endpoint, file);
return this.http.post(this.endpoint, formData); // Problem solved
Added HttpHeaders, I try empty headers, undefined and other propose solution from stackoverflow and google.
const header = new HttpHeaders() //1
header.append('enctype', 'multipart/form-data'); //2
header.append('Content-Type', 'multipart/form-data'); //3
If I put httpheader with resources in request, server gives 415 (unsupported media type)
I try HttpRequest from '@angular/common/http' which finally give me result that i want.
const formData: FormData = new FormData();
formData.append('file', file, file.name);
const req = new HttpRequest('POST', this.endpoint, formData);
return this.http.request(req);
I want to know is it a bug or my misunderstanding? If you check online tutorial, most of the developers use "this.HttpClient.post". From what I read, I can use httpclient.post and angular framework will auto set the proper header for user. It seems like it's not doing the job.
After thorough investigation, first error is my mistake of using file instead of formData, second error is header "content-type" declare in httpinterceptor which after removed, it load the file as expected.
@Injectable()
export class JwtInterceptor implements HttpInterceptor {
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// add authorization header with jwt token if available
// if (request.url.indexOf('/upload')) {
// return next.handle(request);
// }
const token = localStorage.getItem('token');
const currentUser = JSON.parse(localStorage.getItem('user'));
if (currentUser && token) {
request = request.clone({
setHeaders: {
Authorization: `Bearer ${token}`,
// 'Content-Type': 'application/json' <---- Main Problem.
}
});
}
return next.handle(request).pipe(catchError(err => this.handleError(err)));
}
}
Server: "https://github.com/phonemyatt/TestPlaygroundServer"
Client: "https://github.com/phonemyatt/TestPlayground"
Upvotes: 2
Views: 9577
Reputation: 20092
Below code work for you
uploadSecond(file: File) {
const formData: FormData = new FormData();
formData.append('file', file, file.name);
return this.http.post('https://localhost:44393/api/fileupload/UploadSecond', formData);
}
Then in your controller
[HttpPost("UploadSecond")]
[DisableRequestSizeLimit]
public async Task<IActionResult> UploadSecond([FromForm]IFormFile file)
Upvotes: 2
Reputation: 174
If you are using FormData in client you can get files like this.
[HttpPost("Upload"), DisableRequestSizeLimit]
public ActionResult Upload()
{
try
{
var file = Request.Form.Files[0];
var folderName = Path.Combine("Resources","Images");
var pathToSave = Path.Combine(Directory.GetCurrentDirectory(), folderName);
if (file.Length > 0)
{
var fileName = ContentDispositionHeaderValue.Parse(file.ContentDisposition).FileName.Trim('"');
var fullPath = Path.Combine(pathToSave, fileName);
var dbPath = Path.Combine(folderName, fileName);
using (var stream = new FileStream(fullPath, FileMode.Create))
{
file.CopyTo(stream);
}
return Ok(new { dbPath });
}
else
{
return BadRequest();
}
}
catch (Exception ex)
{
return StatusCode(500, "Internal server error");
}
}
Upvotes: 0
Reputation: 93073
In your first example that doesn't work, you are passing file
into post(...)
instead of formData
. It should be:
const formData: FormData = new FormData();
formData.append('file', file, file.name);
return this.http.post(this.endpoint, formData);
The code you show for the controller appears to be correct, so this should be the only change that's required. You do not need to set any custom headers on the request that is sent from Angular.
Upvotes: 3