Click here to Skip to main content
15,896,063 members
Articles / Web Development / HTML
Tip/Trick

File Upload Using AngularJS and ASP.NET MVC5

Rate me:
Please Sign up or sign in to vote.
4.79/5 (18 votes)
21 Feb 2015CPOL2 min read 209.6K   7.1K   24   46
How to upload file using AngularJS and ASP.NET MVC5? How to upload multiple files using AngularJs and MVC5?

What's This?

The goal of this is as given in the title. It's very simple. Here, I will document the simplest way to upload file using AngularJs and ASP.NET MVC5.

Why is This?

There are so many libraries to do this online. So, what difference will I make? If this question comes to your mind at the very beginning, then cool! Let's have a look at why you must be bothered about this.

My requirement is very simple. I have a Model. Please see below:

C#
public class TutorialModel
    {
        public string Title { get; set; }
        public string Description { get; set; }
        public HttpPostedFileBase Attachment { get; set; }
    }

I want to bind this model from client side with Angular and post it to the ASP.NET MVC5 controller.

Most of the libraries that I found online work in the following way:

  1. Upload file --> Save it --> Return the file URL in response
  2. Send another request with model and file URL

The common problem of this way is: every time you change the file, it will upload the file to the server. Previous files will not be deleted. So I don't want to do this and maybe even you might not want it. I will show how we can do it in one request. Users are free to change anything as many times as they wish. When they will click save, then the Model will be sent to the server.

Form

How is This?

To do this, I will use HTML5 FormData here. I have written a separate Angular module for this so that anyone can use it in their module. Let's have a look in my akFileUploader module.

Download from github.

JavaScript
(function () {

    "use strict"

    angular.module("akFileUploader", [])

           .factory("akFileUploaderService", ["$q", "$http",
               function ($q, $http) {

                   var getModelAsFormData = function (data) {
                       var dataAsFormData = new FormData();
                       angular.forEach(data, function (value, key) {
                           dataAsFormData.append(key, value);
                       });
                       return dataAsFormData;
                   };

                   var saveModel = function (data, url) {
                       var deferred = $q.defer();
                       $http({
                           url: url,
                           method: "POST",
                           data: getModelAsFormData(data),
                           transformRequest: angular.identity,
                           headers: { 'Content-Type': undefined }
                       }).success(function (result) {
                           deferred.resolve(result);
                       }).error(function (result, status) {
                           deferred.reject(status);
                       });
                       return deferred.promise;
                   };

                   return {
                       saveModel: saveModel
                   }}])
         .directive("akFileModel", ["$parse",
                function ($parse) {
                    return {
                        restrict: "A",
                        link: function (scope, element, attrs) {
                            var model = $parse(attrs.akFileModel);
                            var modelSetter = model.assign;
                            element.bind("change", function () {
                                scope.$apply(function () {
                                    modelSetter(scope, element[0].files[0]);
                                });
                            });
                        }
                    };
                }]);
})(window, document);

I will give you a very brief description of what this module does. It has one directive and one factory service.

  • akFileModel directive: It is responsible for changing file and binding it to the modelSetter.
  • akFileUploaderService: It basically creates FormData objects and sends it to the desired URL using $http.

Use in MVC

application.js

JavaScript
"use strict";
(function () {
    angular.module("application", ["ngRoute", "akFileUploader"]);
})();

template

HTML
<form class="form-horizontal">
    <h4>Tutorial</h4>
    <hr />
    <div class="form-group">
        <label for="title" class="col-md-2 control-label">Title</label>
        <div class="col-md-10">
            <input type="text" data-ng-model="tutorial.title" 
            name="title" class="form-control" />
        </div>
    </div>
   <div class="form-group">
        <label for="description" class="col-md-2 control-label">Description</label>
        <div class="col-md-10">
            <textarea data-ng-model="tutorial.description" 
            name="description" class="form-control">
            </textarea>
        </div>
    </div>
   <div class="form-group">
        <label for="attachment" class="col-md-2 control-label">Attachment</label>
        <div class="col-md-10">
            <input type="file" name="attachment" 
            class="form-control" data-ak-file-model="tutorial.attachment" />
        </div>
    </div>
  <div class="form-group">
        <div class="col-md-offset-2 col-md-10">
            <input type="button" class="btn btn-primary" 
            value="Save" data-ng-click="saveTutorial(tutorial)" />
        </div>
    </div>
</form>

service

JavaScript
"use strict";
(function () {
    angular.module("application")
           .factory("entityService", 
           ["akFileUploaderService", function (akFileUploaderService) {
               var saveTutorial = function (tutorial) {
                   return akFileUploaderService.saveModel(tutorial, "/controllerName/actionName");
               };
               return {
                   saveTutorial: saveTutorial
               };
           }]);
})();

controller(js)

JavaScript
"use strict";
(function () {
    angular.module("application")
           .controller("homeCtrl", ["$scope", "entityService",
               function ($scope, entityService) {
                   $scope.saveTutorial = function (tutorial) {
                       entityService.saveTutorial(tutorial)
                                    .then(function (data) {
                                        console.log(data);
                                    });
                   };
               }]);
})();

MVC Controller Action

C#
[HttpPost]
public ActionResult SaveTutorial(TutorialModel tutorial)
    {
        return Json("Tutorial Saved",JsonRequestBehavior.AllowGet);
    }

Uploading Multiple files

In order to upload multiple files, You have to change something. In input field, allow multiple.

HTML
<input type="file" name="attachment" class="form-control" 
data-ak-file-model="tutorial.attachment" multiple />

In akFileUploader module, update the getModelAsFormData of akFileUploaderService.

JavaScript
var getModelAsFormData = function (data) {
                       var dataAsFormData = new FormData();
                       angular.forEach(data, function (value, key) {
                           if (key == "attachment") {
                               console.log(value);
                               for (var i = 0; i < value.length; i++) {
                                   dataAsFormData.append(value[i].name, value[i]);
                               }
                           } else {
                               dataAsFormData.append(key, value);
                           }
                       });
                       return dataAsFormData;
                   };

Here, I have appended all files in form data by attachment key. You will notice that my input name is attachment. So if you change it, then keep the same name in getModelAsFormData as well.

JavaScript
modelSetter(scope, element[0].files);

Write the above line instead of following in akFileModel directive:

JavaScript
modelSetter(scope, element[0].files[0]);

Now receive the files in controller in the following way...

C#
[HttpPost]
       public ActionResult SaveTutorial(TutorialModel tutorial)
       {
           foreach (string file in Request.Files)
           {
               var fileContent = Request.Files[file];
               if (fileContent != null && fileContent.ContentLength > 0)
               {
                   var inputStream = fileContent.InputStream;
                   var fileName = Path.GetFileName(file);
                   var path = Path.Combine(Server.MapPath("~/App_Data/Images"), fileName);
                   using (var fileStream = System.IO.File.Create(path))
                   {
                       inputStream.CopyTo(fileStream);
                   }
               }
           }
           return Json("Tutorial Saved",JsonRequestBehavior.AllowGet);
       }

So I am done. Start using it. Thanks!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Instructor / Trainer Jashore University of Science and Technology
Bangladesh Bangladesh
2016 Microsoft MVP

Currently, I am devoted to provide technical and development support to the SharePoint clients and also I am working on angularjs. I am experienced with C#, ASP.NET, SharePoint, SignalR, angularjs, MS SQL, Oracle 11g R2, Windows Phone, Firefox OS and so on. I have fallen in love with many technologies but never got married to any of them. I am evolving myself as full stack developer. I always like to share knowledge as much as to gather from you.

Comments and Discussions

 
GeneralRe: Getting error while upload large file Pin
Member 105711069-Sep-15 2:37
Member 105711069-Sep-15 2:37 
GeneralRe: Getting error while upload large file Pin
Atish Dipongkor9-Sep-15 2:54
professionalAtish Dipongkor9-Sep-15 2:54 
QuestionMultiple Files upload Pin
saravana kumar B21-Aug-15 5:16
saravana kumar B21-Aug-15 5:16 
AnswerRe: Multiple Files upload Pin
Atish Dipongkor22-Aug-15 8:49
professionalAtish Dipongkor22-Aug-15 8:49 
NewsRe: Multiple Files upload Pin
Atish Dipongkor9-Sep-15 6:29
professionalAtish Dipongkor9-Sep-15 6:29 
QuestionI'm doing the same Pin
Member 100704595-Aug-15 2:58
Member 100704595-Aug-15 2:58 
AnswerRe: I'm doing the same Pin
Atish Dipongkor5-Aug-15 3:58
professionalAtish Dipongkor5-Aug-15 3:58 
GeneralRe: I'm doing the same Pin
Member 100704595-Aug-15 5:00
Member 100704595-Aug-15 5:00 
GeneralRe: I'm doing the same Pin
Atish Dipongkor5-Aug-15 6:12
professionalAtish Dipongkor5-Aug-15 6:12 
GeneralRe: I'm doing the same Pin
Member 100704595-Aug-15 5:03
Member 100704595-Aug-15 5:03 
GeneralRe: I'm doing the same Pin
Atish Dipongkor5-Aug-15 6:16
professionalAtish Dipongkor5-Aug-15 6:16 
GeneralRe: I'm doing the same Pin
Member 100704595-Aug-15 6:32
Member 100704595-Aug-15 6:32 
GeneralRe: I'm doing the same Pin
Member 100704595-Aug-15 6:40
Member 100704595-Aug-15 6:40 
SuggestionRe: I'm doing the same Pin
Atish Dipongkor5-Aug-15 7:43
professionalAtish Dipongkor5-Aug-15 7:43 
GeneralRe: I'm doing the same Pin
Member 100704595-Aug-15 22:43
Member 100704595-Aug-15 22:43 
QuestionMultiple file upload Pin
Member 1185410922-Jul-15 0:10
Member 1185410922-Jul-15 0:10 
AnswerRe: Multiple file upload Pin
Atish Dipongkor22-Jul-15 3:55
professionalAtish Dipongkor22-Jul-15 3:55 
QuestionGetting Error "No MediaTypeFormatter is available to read an object of type '<MyModelName>' from content with media type 'multipart/form-data'" Pin
webden22-Apr-15 0:12
webden22-Apr-15 0:12 
AnswerRe: Getting Error "No MediaTypeFormatter is available to read an object of type '<MyModelName>' from content with media type 'multipart/form-data'" Pin
Atish Dipongkor6-May-15 6:43
professionalAtish Dipongkor6-May-15 6:43 
GeneralMy vote of 1 Pin
Member 1139264123-Feb-15 9:45
Member 1139264123-Feb-15 9:45 
GeneralRe: My vote of 1 Pin
Atish Dipongkor26-Feb-15 18:06
professionalAtish Dipongkor26-Feb-15 18:06 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.