phonemyatt
phonemyatt

Reputation: 1377

Unable to File Upload From Angular 8 to Asp.net Core 2.2

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".

  1. 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
    

400 Bad Request NULL FILE

  1. 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)

415 Bad Request Unsupported Media Type

  1. 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

Answers (3)

Tony
Tony

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

gkhnclk
gkhnclk

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

Kirk Larkin
Kirk Larkin

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

Related Questions