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

File Upload Using AngularJS and ASP.NET MVC5

0.00/5 (No votes)
21 Feb 2015 2  
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:

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.

(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

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

template

<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

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

"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

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

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

In akFileUploader module, update the getModelAsFormData of akFileUploaderService.

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.

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

Write the above line instead of following in akFileModel directive:

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

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

[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 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