In this post, I'll show you how to upload a file in AngularJS with ASP.Net Web API. As you know, file upload is an indispensable feature in web applications.

However, if you are uploading files using web api in the AngularJS you need to use the library for the AngularJS or use the directive to resolve the problem HttpPostedFileBase is always null when doing HttpPost.

To practice you need to create a Web API method lets you to upload files to your IIS server as the following.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace Invoice.Controllers
{
    [Authorize]
    public class UploadController : Controller
    {
        [HttpPost]
        public JsonResult File(HttpPostedFileBase file)
        {
            string path = HttpContext.Server.MapPath($"~/bin/Files");
            if (!Directory.Exists(path))
                Directory.CreateDirectory(path);
            if (file != null && file.ContentLength > 0)
            {
                if (!System.IO.File.Exists($"{path}/{file.FileName}"))
                {
                    file.SaveAs(Path.Combine(path, Path.GetFileName(file.FileName)));
                    return Json(new { filename = file.FileName });
                }
                return Json(new { filename = "exist" });
            }
            return Json(new { filename = "null" });
        }
    }
}

If we upload the file successfully we will return the file name, otherwise it will be 'null' or 'exist' if the file already exists on the server.

To upload file in AngularJS, you should install upload file for AngularJS, then include to your shared layout or index.html

using System.Web;
using System.Web.Optimization;

namespace Invoice
{
    public class BundleConfig
    {
        // For more information on bundling, visit https://go.microsoft.com/fwlink/?LinkId=301862
        public static void RegisterBundles(BundleCollection bundles)
        {           
            //...

            bundles.Add(new ScriptBundle("~/main/js").Include(                
                "~/Scripts/angular.min.js",
                "~/Scripts/angular-route.min.js",
                "~/Scripts/angular-ui/ui-bootstrap-tpls.min.js",
                "~/Scripts/angular-animate.min.js",
                "~/Scripts/toaster.min.js",
                "~/Scripts/ng-file-upload.js",
                "~/Scripts/ng-file-upload-shim.js",
                "~/app/app.js",
                "~/app/controllers/invoiceTemplateController.js"));
        }
    }
}

You can install ng-file-upload.js from Nuget Package Manager or you can download it directly from https://github.com/danialfarid/ng-file-upload, then create a controller to upload file in AngularJS as show belown.

(function () {
    'use strict';

    angular
        .module('app')
        .controller('invoiceTemplateController', invoiceTemplateController);

    invoiceTemplateController.$inject = ['$scope', '$uibModal', 'toaster', 'Upload'];

    function invoiceTemplateController($scope, $modal, toaster, Upload) {

        $scope.upload = function (file) {
            if (file === undefined) {
                toaster.error('Error', 'Please select your file to upload!');
                return;
            }
            Upload.upload({
                url: '/Upload/File',
                method: 'POST',
                data: { file: file }
            }).then(function (response) {
                if (response.data.filename === 'null') {
                    toaster.error('Error', 'Your upload file is invalid!');
                    return;
                }
                if (response.data.filename === 'exist') {
                    toaster.error('Error', 'Your upload file already exists on the server!');
                    return;
                }
                var fileName = response.config.data.file.name;
            }, function (error) {
                toaster.error("Error", error.status);
            }, function (evt) { });
        };

        $scope.fileUpload = function (invoiceTemplate) {
            $scope.invoiceTemplate = invoiceTemplate;
            $scope.modalInstance = $modal.open({
                animation: false,
                templateUrl: 'app/views/invoicetemplate/fileupload.min.html',
                controller: 'invoiceTemplateController',
                scope: $scope,
                size: 'md',
                backdrop: false,
                resolve: {
                    invoiceTemplate: function () {
                        return $scope.invoiceTemplate;
                    }
                }
            });
        }

        $scope.cancel = function () {
            $scope.modalInstance.close();
        }
    }
})();

and view upload file

<div class="modal-primary">
    <div class="modal-content">
        <div class="modal-header">
            <button type="button" class="close" data-dismiss="modal" ng-click="cancel()" aria-hidden="true">×</button>
            <h4 class="modal-title">Upload file</h4>
        </div>
        <div class="modal-body">
            <form name="form" role="form">
                <div class="row">
                    <div class="col-sm-12">
                        <div class="form-group">
                            <label for="templateCode">File name</label>
                            <input class="form-control" type="file" ngf-select ng-model="file" name="file" ngf-max-size="2MB" required />
                        </div>
                    </div>
                </div>
            </form>
        </div>
        <div class="modal-footer">
            <button type="button" ng-click="upload(file, invoiceTemplate)" class="btn btn-primary">Upload</button>
            <button type="button" class="btn btn-warning" data-dismiss="modal" ng-click="cancel()">Hủy</button>
        </div>
    </div>
</div>

and don't forget to add support multipart/form-data to the WebApiConfig.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http.Headers;
using System.Web.Http;

namespace Invoice
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // Web API configuration and services
            config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("multipart/form-data"));

            // Web API routes
            config.MapHttpAttributeRoutes();

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{action}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
        }
    }
}