17

I have a problem here when I am trying to push data with angularjs controller. But what ever I do (IFormFile file) is always empty. There are only some examples with razor syntax but no examples how to do it with angular or jquery.

HTML:

<form class="form-body" enctype="multipart/form-data" name="newFileForm" ng-submit="vm.addFile()"><input type="file" id="file1" name="file" multiple ng-files="getTheFiles($files)"/></form>

Directive:

(function() {
'use strict';

angular
    .module('app')
    .directive('ngFiles', ['$parse', function ($parse) {

    function fn_link(scope, element, attrs) {
        var onChange = $parse(attrs.ngFiles);
        element.on('change', function (event) {
            onChange(scope, { $files: event.target.files });
        });
    };

    return {
        link: fn_link
    };
    }]);
})();

Controller

var formdata = new FormData();
    $scope.getTheFiles = function ($files) {
        angular.forEach($files, function (key, value) {
            formdata.append(key, value);
        });
    };

vm.addFile = function () {                                              
        var xhr = new XMLHttpRequest();
        xhr.open('POST', url, true);
        xhr.setRequestHeader("Content-Type", "undefined");
        xhr.send(formdata);          
    }

Asp.net core webapi:

[HttpPost]
    public async Task<IActionResult> PostProductProjectFile(IFormFile file)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        ....
        return ...;
    }

I have also tried to do it with formdata, as it is constructed when you post it with razor syntax. Something like this:

dataService.addFile(formdata, {
            contentDisposition: "form-data; name=\"files\"; filename=\"C:\\Users\\UserName\\Desktop\\snip_20160420091420.png\"",
            contentType: "multipart/form-data",
                    headers: {
                        "Content-Disposition": "form-data; name=\"files\"; filename=\"C:\\Users\\UserName\\Desktop\\snip_20160420091420.png\"",
                        'Content-Type': "image/png"
                    },
                    fileName: "C:\\Users\\UserName\\Desktop\\snip_20160420091420.png",
                    name: "files",
                    length : 3563
            }

Also instead of formData to provide raw file as I wrote in comment. But still nothing happens

error505
  • 1,126
  • 1
  • 17
  • 29
  • it would help if you could share how your request body looks like (i am not interested in the posted file content but everything else). You can grab it from a browser's developer tool diagnostics. – Kiran Jul 01 '16 at 18:37
  • This is when it is rawfile `lastModified:1461136463443 lastModifiedDate:Wed Apr 20 2016 09:14:23 GMT+0200 (W. Europe Daylight Time) name:"snip_20160420091420.png" size:3563 type:"image/png" webkitRelativePath:""` And when it is form data than I cant read it, it is just `__proto__:FormData` – error505 Jul 04 '16 at 06:34

4 Answers4

45

IFormFile will only work if you input name is the same as your method parameter name. In your case the input name is 'files' and the method parameter name is 'file'. Make them the same and it should work.

Tony Steele
  • 451
  • 4
  • 2
  • 3
    I've been trying to figure this out for hours, and this was the missing piece, for me. – Quanta Sep 15 '17 at 20:33
  • Thank you dude! Holly crap been struggling on that for ages. – Yodacheese Oct 11 '17 at 03:13
  • I've struggled for a few days with this. For some reason it just does not work, running dotnet core 2.1 API controller. The accepted answer works. – Talnaci Sergiu Vlad Jul 18 '18 at 09:38
  • amazing brilliant answer – Rohit Kumar Dec 29 '20 at 17:58
  • I am having a very bad headache trying to figure this out, finally I see the smallest answer by mistake, which turned out to be the only missing info. I think this is stupid because I am uploading a list of files, but one file name is file. – aah134 Sep 13 '22 at 19:26
26

This is how to do it with angularjs:

vm.addFile = function () {                      
                var fileUpload = $("#file").get(0);
                var files = fileUpload.files;
                var data = new FormData();
                for (var i = 0; i < files.length ; i++) {
                    data.append(files[i].name, files[i]);
                }


                $http.post("/api/Files/", data, {
                    headers: { 'Content-Type': undefined },
                    transformRequest: angular.identity
                }).success(function (data, status, headers, config) {

                }).error(function (data, status, headers, config) {

                });
}

And in web Api:

[HttpPost]
public async Task<IActionResult> PostFile()
{
 //Read all files from angularjs FormData post request
 var files = Request.Form.Files;
 var strigValue = Request.Form.Keys;
 .....
}

Or like this:

    [HttpPost]
    public async Task<IActionResult>  PostFiles(IFormCollection collection)
    {
        var f = collection.Files;                         

            foreach (var file in f)
            {
                //....
             }           
    }
error505
  • 1,126
  • 1
  • 17
  • 29
  • Thanks, Its also work without " transformRequest: angular.identity", just add " 'Content-Type': undefined " is enough. – Hasan Nafisi Jul 22 '18 at 20:15
2

You can do it also with kendo upload much simpler:

$("#files").kendoUpload({
        async: {
            saveUrl: dataService.upload,
            removeUrl: dataService.remove,
            autoUpload: false                                            
        },
        success: onSuccess,
        files: files
    });
1

From the answer of @Tony Steele. Here is the code sample (Where to change/take care of)

.NET Core 3.1 LTS

[Route("UploadAttachment")]
[HttpPost]
public async Task<IActionResult> UploadAttachment(List<IFormFile> formFiles)
{
    return Ok(await _services.UploadAttachment(formFiles));
}

AngularJS

var formFiles = new FormData();
if ($scope.files != undefined) {
    for (var i = 0; i < $scope.files.length; i++) {
       formFiles.append('formFiles', $scope.files[i]);
    }
}