Monday, August 12, 2019

Using Post method in Angular 4 to Upload Multiple Files with Web API

Multiple File Upload Example in Angular 4 using Web API in MVC 4
I have shared a post on HttpClient service in Angular 4 recently, where I have explained how to use the get() method of HttpClient object to access data from a Web API method. Here in this example, you will see how to send data (multiple files in this case) to a Web API using HttpClient post() method.
The data that we will send (to the Web API) is a FormData object, populated with files. Therefore, you will also learn how to post a FormData object in Angular 4.
The process is very simple. Stay with me.
First, we’ll create the Web API controller using Asp.Net C# and Vb.Net in MVC 4.

The Web API Controller in Asp.Net

I have only defined a Controller in my Web API for uploading files, which has a public function named UploadFiles of type String that will receive files sent from a client app. The function uses the HttpFileCollection class of system.io interface, to collection information about files and would save them in a folder (named locker). It will return a message (a string) after completing the process. The message could be a success or an error.
There are no Models.
FileUploadController.cs (for C#)
using System;

using System.Net.http;
using System.Web.http;

using System.IO;

namespace FileUpload
{
    public class FileUploadController : ApiController
    {
        [HttpPost()]
        public string UploadFiles()
        {
            int iUploadedCnt = 0;

            // DEFINE THE PATH WHERE WE WANT TO SAVE THE FILES.
            string sPath = "";
            sPath = System.Web.Hosting.HostingEnvironment.MapPath("~/locker/");

            System.Web.HttpFileCollection hfc = System.Web.HttpContext.Current.Request.Files;

            // CHECK THE FILE COUNT.
            for (int iCnt = 0; iCnt <= hfc.Count - 1; iCnt++)
            {
                System.Web.HttpPostedFile hpf = hfc[iCnt];

                if (hpf.ContentLength > 0)
                {
                    // CHECK IF THE SELECTED FILE(S) ALREADY EXISTS IN FOLDER. (AVOID DUPLICATE)
                    if (!File.Exists(sPath + Path.GetFileName(hpf.FileName)))
                    {
                        // SAVE THE FILES IN THE FOLDER.
                        hpf.SaveAs(sPath + Path.GetFileName(hpf.FileName));
                        iUploadedCnt = iUploadedCnt + 1;
                    }
                }
            }

            // RETURN A MESSAGE.
            if (iUploadedCnt > 0) {
                return iUploadedCnt + " Files Uploaded Successfully";
            }
            else {
                return "Upload Failed";
            }
        }
    }
}
FileUploadController.cs (for Vb)
Option Explicit On

Imports System.Net.http
Imports System.Web.http
Imports System.IO

Namespace FileUpload
    Public Class FileUploadController
        Inherits ApiController

        <HttpPost()> _
        Public Function UploadFiles() As String

            Dim iUploadedCnt As Integer = 0

            ' DEFINE THE PATH WHERE WE WANT TO SAVE THE FILES.
            Dim sPath As String = ""
            sPath = System.Web.Hosting.HostingEnvironment.MapPath("~/locker/")

            Dim hfc As System.Web.HttpFileCollection = System.Web.HttpContext.Current.Request.Files

            For iCnt As Integer = 0 To hfc.Count - 1        ' CHECK THE FILE COUNT.
                Dim hpf As HttpPostedFile = hfc(iCnt)
                If hpf.ContentLength > 0 Then

                    ' CHECK IF THE SELECTED FILE(S) ALREADY EXISTS IN FOLDER. (AVOID DUPLICATE)
                    If Not File.Exists(sPath & Path.GetFileName(hpf.FileName)) Then

                        ' SAVE THE FILES IN THE FOLDER.
                        hpf.SaveAs(sPath & Path.GetFileName(hpf.FileName))
                        iUploadedCnt = iUploadedCnt + 1
                    End If
                End If
            Next

            If Val(iUploadedCnt) > 0 Then
                Return iUploadedCnt & " Files Uploaded Successfully"
            Else
                Return "Upload Failed"
            End If

        End Function
    End Class
End Namespace
Note: Now run the API and keep this running. For example,
http://localhost:[someport]/api/fileupload
I’ll be using the entire url in my Angular component with the post() method.

Create Angular 4 Project

Open the command (cmd) prompt go to the folder where want to create the project and type,
ng new multiple-file-upload-in-angular
Now launch the server. Go to the folder you just created above and type,
ng serve --open (or --o)

Import HttpClinetModule to the Project

Open app.module.ts file under src/app folder, copy the code and paste it.
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';

import { HttpClientModule } from '@angular/common/https';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    HttpClientModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }
Now, import HttpClient service to your components.

Create HttpClient Component to use POST Method

I’ll now add the HttpClient class inside the app.compontent.ts file. In here, I have two methods, which I have defined, namely, getFileDetails and uploadFiles.
The getFileDetails() method will be called when I select files from my application template using the file <input> type element.
In the uploadFiles() method, I am using a FormData constructor to create object, where I’ll append (or add) the files. This method is called when I click a <button> in the application template.
After collecting the files and appending them to the FormData object, I’ll post (or send) the data to the file upload Web API controller, using the post() method of HttpClient class.
Copy the code and paste it in your app.components.ts file.
import { Component, OnInit } from '@angular/core';
import { HttpClient } from '@angular/common/https';
import { HttpErrorResponse } from '@angular/common/https/src/response';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'Upload Multiple Files in Angular 4';

  constructor (private httpService: HttpClient) {  }

  myFiles:string [] = [];
  sMsg:string = '';

  ngOnInit () {  }

  getFileDetails (e) {
    //console.log (e.target.files);
    for (var i = 0; i < e.target.files.length; i++) { 
      this.myFiles.push(e.target.files[i]);
    }
  }

  uploadFiles () {
    const frmData = new FormData();
    
    for (var i = 0; i < this.myFiles.length; i++) { 
      frmData.append("fileUpload", this.myFiles[i]);
    }
    
    this.httpService.post('http://localhost:60505/api/fileupload/', frmData).subscribe(
      data => {
        // SHOW A MESSAGE RECEIVED FROM THE WEB API.
        this.sMsg = data as string;
        console.log (this.sMsg);
      },
      (err: HttpErrorResponse) => {
        console.log (err.message);    // Show error, if any.
      }
    );
  }
}
Now create the application template.
The Template
<div>
    <h1>
        {{title}}!
    </h1>

    <ng-container>
        <input type="file" id="file" multiple 
            (change)="getFileDetails($event)">

        <button (click)="uploadFiles()">Upload</button>
    </ng-container>
</div>
That’s it. Now save the Angular 4 project and go the browser. You have already the launched the server and app is running. Choose your files and click the upload button.

No comments:

Post a Comment

No String Argument Constructor/Factory Method to Deserialize From String Value

  In this short article, we will cover in-depth the   JsonMappingException: no String-argument constructor/factory method to deserialize fro...