Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Multiple File Upload using AngularJS and ASP.net MVC

0.00/5 (No votes)
11 Nov 2015 1  
This article describes multiple file upload process with AngularJS and ASP.net MVC and tracking individual file's upload progress

Source Code

Introduction

From last few days i am trying upload multiple image with Angular and ASP.net MVC. i also want to track the individual file's upload progress. I google a lot. Found lot of code but some do not work. After 6 days hard work at last i found the proper way. I did not get one place where all  the things grather.(may be my searching capability is low). So here i aim to grather all the thing in one place that may help you to learn the process of uploading multiple file using angularJS and asp.net MVC. Lets Start

Description

I assume that you have konowledge on how to use AngularJS. I also assume that you have knowledge on Twitter Bootstrap ,Font Awesome. HTML5 and CSS3. I will proced step by step

Step 1: Prepare HTML file and Show Selected File Information

we use HTML input tag to input multiple/single file upload. The HTML file is as follows

<html ng-app="AgApp">
<head>
    <meta name="viewport" content="width=device-width" />
    <title>ImageUploadMultiple</title>
    <link href="~/App_Content/CSS/bootstrap.min.css" rel="stylesheet" />
    <link href="~/App_Content/CSS/font-awesome.min.css" rel="stylesheet" />
</head>
<body>
     <div class="col-md-12">
        <h2>Image/File Upload With Angular::</h2>
    </div>

    <div ng-controller="ImageUploadMultipleCtrl">

        <div class="col-md-12" style="text-align:center;margin-bottom:10px;">
            <input type="file" id="file" name="file" multiple onchange="angular.element(this).scope().setFile(this)" accept="image/*" class="btn btn-warning" /> 
        </div>
        <div class="col-md-12">
            <button ng-click="UploadFile()" class="btn btn-primary" >Upload File</button>
        </div>
        
        <div class="col-md-12" style="padding-top:10px;">

                <div class="col-md-7">
                    <table class="table table-bordered table-striped">
                        <thead>
                            <tr>
                                <th>File Name</th>
                                <th>File Type</th>
                                <th>File Size</th>
                                <th>Status</th>
                            </tr>
                        </thead>
                        <tbody>
                            <tr ng-repeat="file in fileList">

                                <td>{{file.file.name}}</td>
                                <td>{{file.file.type}}</td>
                                <td>{{file.file.size}}</td>
                                <td>
                                    <div id="{{'P'+$index}}">
                                        
                                    </div>
                                </td>

                            </tr>
                        </tbody>
                    </table>
                </div>
            </div>
     </div>
    <!-- Loading JQuery-->
    <script src="~/App_Content/JS/jquery-1.7.2.min.js"></script>
    <script src="~/App_Content/JS/jquery.unobtrusive-ajax.min.js"></script>
    <!-- Lodaing the Angular JS-->
    <script src="~/App_Content/JS/angular.min.js"></script>
    
    <!-- Load our Angular Application-->
    <script src="~/App_Content/JS/Practical/Module.js"></script>
    <!-- Load the page Controller-->
    <script src="~/App_Content/JS/Practical/ImageUploadMultipleController.js"></script>
</body>
</html>
  1.  ng-app="AgApp" we bootstrap an Angular application
  2. ng-controller="ImageUploadMultipleCtrl"  specifiy the controller for this page that contain the code for show slected file information and file upload function

  3. <input type="file" id="file" name="file" multiple onchange="angular.element(this).scope().setFile(this)"> enable us to input multiple file. And the onchange event we call setFile function which is an angular function. This function collects all files you selected and put into a $scope variable name fileList.

  4. as soon as file information save at  fileList. we loop through the fileList by <tr ng-repeat="file in fileList"> to show the file information.

  5. Each file have 3 auto property name,type and size. This 3 property of file you can access direcly.

now move to our controller and lets develop the setFile() function to set the fileList. As soon as we set the fileList with your selected image , Angular show the selected file infomation imediately. That's is the magic of Angular auto binding.

First we have to difine angular module. In Module.js File we did this. here is Module.js file

var app = angular.module('AgApp', [])

now use this module to develop our Angular controller for file upload. following code is a angular controler with SetFile() finction. The file ImageUploadMultipleController.js is as follows

app.controller('ImageUploadMultipleCtrl', function ($scope) {

    $scope.fileList = [];
    $scope.curFile;
    $scope.ImageProperty = {
        file:''
    }

    $scope.setFile = function (element) {
        $scope.fileList = [];
       // get the files
        var files = element.files;
        for(var i=0;i<files.length;i++)
        {
            $scope.ImageProperty.file = files[i];
            
            $scope.fileList.push($scope.ImageProperty);
            $scope.ImageProperty = {};
            $scope.$apply();
          
        }
    }

});

here ImageUploadMultipleCtrl is our controller name. The $scope variable fileList is an array of files that you selected. This end our step1, Run the project  and slelect multiple file by press Ctrl key and you will find the following effect. Dont forget to add Module.js  and imageUploadMultipleController.js at the end our page as shown in the above Html file.

Step 2: Develop Upload functionality With XMLHttpRequest

we will develop  our upload function with XMLHttpRequest. XMLHttpRequest is an API that provides client functionality for transferring data between a client and a server. It provides an easy way to retrieve data from a URL without having to do a full page refresh. XMLHttpRequest was originally designed by Microsoft and adopted by Mozilla, Apple, and Google. For get more information XMLHttpRequest refer to 

https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest

I chose XMLHttpRequest for the following reasons

  1. It provide us asynchronous upload of multiple files
  2. It provides tha way for tracking the progress of each files

Lets start developing our code. After completing Step1 we got all file in array named fileList. so loop through the fileList and get each file from the list with name,size and type  and send all to another function to upload. so add two function at our controller at imageUploadMultipleController.js

  1. UploadFile() -- this function call when we click upload button. 
  2. UploadFileIndividual(fileToUpload,name,type,size,index) -- responsible for upload indivudual file. it take 4 parameter: the file to upload,the file name,the file type ,file size and index 
$scope.UploadFile=function()
    {

        for (var i = 0; i < $scope.fileList.length; i++)
        {

            $scope.UploadFileIndividual($scope.fileList[i].file,
                                        $scope.fileList[i].file.name,
                                        $scope.fileList[i].file.type,
                                        $scope.fileList[i].file.size,
                                        i);
        }

    }

 

$scope.UploadFileIndividual = function (fileToUpload,name,type,size,index)
    {
        //Create XMLHttpRequest Object
        var reqObj = new XMLHttpRequest();

       //open the object and set method of call(get/post), url to call, isAsynchronous(true/False)
        reqObj.open("POST", "/FileUpload/UploadFiles", true);

       //set Content-Type at request header.for file upload it's value must be multipart/form-data
        reqObj.setRequestHeader("Content-Type", "multipart/form-data");

        //Set Other header like file name,size and type
        reqObj.setRequestHeader('X-File-Name', name);
        reqObj.setRequestHeader('X-File-Type', type);
        reqObj.setRequestHeader('X-File-Size', size);

        // send the file
        reqObj.send(fileToUpload);

    }

That's all . The commnet is well enough to describe the code. The result of this step can not visible with out develop ASP.net MVC controller to receive the object send by XMLHttpRequest.

Step 3: Develop ASP.net MVC Controller

Now we have to develop a ASP.net MVC controller to receive the file send from the XMLHttpRequest object

[HttpPost]
public virtual string UploadFiles(object obj)
{
    var length = Request.ContentLength;
    var bytes = new byte[length];
    Request.InputStream.Read(bytes, 0, length);

    var fileName = Request.Headers["X-File-Name"];
    var fileSize = Request.Headers["X-File-Size"];
    var fileType = Request.Headers["X-File-Type"];

    var saveToFileLoc = "\\\\adcyngctg\\HRMS\\Images\\" + fileName;

    // save the file.
    var fileStream = new FileStream(saveToFileLoc, FileMode.Create, FileAccess.ReadWrite);
    fileStream.Write(bytes, 0, length);
    fileStream.Close();

    return string.Format("{0} bytes uploaded", bytes.Length);
}

now if we run the project and click upload file button after selecting the image, we will find all the image uploaded successfully . But we do not get any message or progress. Let's move to next step where we develop the event handler for XMLHttpRequest object

Step 4: Traceing progress of individual file Upload

XMLHttpRequest object returns status of each event of each file. By writing a event handlar function we can access return status. We can use addEventListener method of XMLHttpRequest object  to handle event . XMLHttpRequest  raise following event at the different status of uploading

  1. progress : it  raise during upload process and send us necessary information on progress status
  2. load : it  raise after uploaded file saved at destination and server send back a response
  3. error : it  raise imediately if any error occurs during upload
  4. abort : it  raise imediately if user cancel the upload process

To handle the progress we have to define 

/*
the following command catch the progress event and pass it to our own function named 
uploadProgress.
*/
reqObj.upload.addEventListener("progress", uploadProgress, false)

function uploadProgress(evt) {
            if (evt.lengthComputable) {
               
               var uploadProgressCount = Math.round(evt.loaded * 100 / evt.total);
           
               document.getElementById('P' + index).innerHTML = uploadProgressCount;

              // when upload complete then show a spiner icon till the server send back a response
               if(uploadProgressCount==100)
               {
                   document.getElementById('P' + index).innerHTML =

                  '<i class="fa fa-refresh fa-spin" style="color:maroon;"></i>';
               }
                
            }
        }

To handle load complete we have to define

reqObj.addEventListener("load", uploadComplete, false)

function uploadComplete(evt) {
            /* This event is raised when the server  back a response */

            document.getElementById('P' + index).innerHTML = 'Saved';
            $scope.NoOfFileSaved++;
            $scope.$apply();
        }

  To handle error during upload we have to define

reqObj.addEventListener("error", uploadFailed, false)

function uploadFailed(evt) {
            document.getElementById('P' + index).innerHTML = 'Upload Failed..';
        }

To handle upload  cancel we have to define

reqObj.addEventListener("abort", uploadCanceled, false)

function uploadCanceled(evt) {

            document.getElementById('P' + index).innerHTML = 'Canceled....';
        }

That's all. Our upload controller is now ready. The final controller look like this (imageUploadMultipleController.js)

$scope.UploadFileIndividual = function (fileToUpload,name,type,size,index)
    {
        //Create XMLHttpRequest Object
        var reqObj = new XMLHttpRequest();

        //event Handler
        reqObj.upload.addEventListener("progress", uploadProgress, false)
        reqObj.addEventListener("load", uploadComplete, false)
        reqObj.addEventListener("error", uploadFailed, false)
        reqObj.addEventListener("abort", uploadCanceled, false)


       //open the object and set method of call(get/post), url to call, isasynchronous(true/False)
        reqObj.open("POST", "/FileUpload/UploadFiles", true);

       //set Content-Type at request header.For file upload it's value must be multipart/form-data
        reqObj.setRequestHeader("Content-Type", "multipart/form-data");

        //Set Other header like file name,size and type
        reqObj.setRequestHeader('X-File-Name', name);
        reqObj.setRequestHeader('X-File-Type', type);
        reqObj.setRequestHeader('X-File-Size', size);


        // send the file
        reqObj.send(fileToUpload);

        function uploadProgress(evt) {
            if (evt.lengthComputable) {
               
               var uploadProgressCount = Math.round(evt.loaded * 100 / evt.total);
           
               document.getElementById('P' + index).innerHTML = uploadProgressCount;

               if(uploadProgressCount==100)
               {
                   document.getElementById('P' + index).innerHTML = 
                  '<i class="fa fa-refresh fa-spin" style="color:maroon;"></i>';
               }
                
            }
        }

        function uploadComplete(evt) {
            /* This event is raised when the server  back a response */

            document.getElementById('P' + index).innerHTML = 'Saved';
            $scope.NoOfFileSaved++;
            $scope.$apply();
        }

        function uploadFailed(evt) {
            document.getElementById('P' + index).innerHTML = 'Upload Failed..';
        }

        function uploadCanceled(evt) {

            document.getElementById('P' + index).innerHTML = 'Canceled....';
        }

    }

Run the project and you will get the following picture.(Please Change the web.config as shown at Step5)

Step 5: Change the Maximum Upload length is Web.config

In order to uplaod large inage you have change the maximum upload length in Web.config.

In <system.web> section change the http in the following way

<httpRuntime targetFramework="4.5" maxRequestLength="1048576" />

Add/Update <system.webServer> section in the following way

<system.webServer>
    <security>
      <requestFiltering>
        <requestLimits maxAllowedContentLength="1073741824" />
      </requestFiltering>

remind  the value maxRequestLength in <system.web> and maxAllowedContentLength in <system.webserver> must be same. 

Final Word

It tesed it with different types of files. When you test it try to use to different computer. i mean try to select file from a network computer. so that you can find the best result of progress count. Or you can upload the project to a live server and try to upload file from your computer. If run it at you local computer and select file from same computer you may not see the progress count effect as uploading from local mechine to local mechine is very fast. 

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here