87

I have a file in my view

<form id="upload" enctype="multipart/form-data">
   <input type="file" name="fileUpload" id="fileUpload" size="23" />
</form>

and an ajax request

$.ajax({
    url: '<%=Url.Action("JsonSave","Survey")  %>',
    dataType: 'json',
    processData: false,
    contentType: "multipart/mixed",
    data: {
        Id: selectedRow.Id,
        Value: 'some date was added by the user here :))'
    },
    cache: false,
    success: function (data) {}
});

but there is no file in the Request.Files. Whats wrong with the ajax request?

Hakan Fıstık
  • 16,800
  • 14
  • 110
  • 131
CoffeeCode
  • 4,296
  • 9
  • 40
  • 55

5 Answers5

145

Upload files using AJAX in ASP.Net MVC

Things have changed since HTML5

JavaScript

document.getElementById('uploader').onsubmit = function () {
    var formdata = new FormData(); //FormData object
    var fileInput = document.getElementById('fileInput');
    //Iterating through each files selected in fileInput
    for (i = 0; i < fileInput.files.length; i++) {
        //Appending each file to FormData object
        formdata.append(fileInput.files[i].name, fileInput.files[i]);
    }
    //Creating an XMLHttpRequest and sending
    var xhr = new XMLHttpRequest();
    xhr.open('POST', '/Home/Upload');
    xhr.send(formdata);
    xhr.onreadystatechange = function () {
        if (xhr.readyState == 4 && xhr.status == 200) {
            alert(xhr.responseText);
        }
    }
    return false;
}   

Controller

public JsonResult Upload()
{
    for (int i = 0; i < Request.Files.Count; i++)
    {
        HttpPostedFileBase file = Request.Files[i]; //Uploaded file
        //Use the following properties to get file's name, size and MIMEType
        int fileSize = file.ContentLength;
        string fileName = file.FileName;
        string mimeType = file.ContentType;
        System.IO.Stream fileContent = file.InputStream;
        //To save file, use SaveAs method
        file.SaveAs(Server.MapPath("~/")+ fileName ); //File will be saved in application root
    }
    return Json("Uploaded " + Request.Files.Count + " files");
}

EDIT : The HTML

<form id="uploader">
    <input id="fileInput" type="file" multiple>
    <input type="submit" value="Upload file" />
</form>
Ajeesh M
  • 2,092
  • 1
  • 14
  • 18
55

AJAX file uploads are now possible by passing a FormData object to the data property of the $.ajax request.

As the OP specifically asked for a jQuery implementation, here you go:

<form id="upload" enctype="multipart/form-data" action="@Url.Action("JsonSave", "Survey")" method="POST">
    <input type="file" name="fileUpload" id="fileUpload" size="23" /><br />
    <button>Upload!</button>
</form>
$('#upload').submit(function(e) {
    e.preventDefault(); // stop the standard form submission

    $.ajax({
        url: this.action,
        type: this.method,
        data: new FormData(this),
        cache: false,
        contentType: false,
        processData: false,
        success: function (data) {
            console.log(data.UploadedFileCount + ' file(s) uploaded successfully');
        },
        error: function(xhr, error, status) {
            console.log(error, status);
        }
    });
});
public JsonResult Survey()
{
    for (int i = 0; i < Request.Files.Count; i++)
    {
        var file = Request.Files[i];
        // save file as required here...
    }
    return Json(new { UploadedFileCount = Request.Files.Count });
}

More information on FormData at MDN

Rory McCrossan
  • 331,213
  • 40
  • 305
  • 339
  • 7
    Beautiful. Thank you! Best answer I have found on SEVERAL questions. – Jess Sep 12 '16 at 19:55
  • 1
    Came here specifically looking for jQuery solution and was a little disappointed in seeing that the response marked as Answered only used vanilla JavaScript. Your solution is great and works very well for me. Thanks very much :) – Joshua K Dec 27 '18 at 16:19
  • Note that if you don't select a file, you still seem to get a single file in the array, with ContentLength = 0 – Savage May 13 '19 at 09:42
  • 1
    @Savage : tested in 2020 / chrome / asp net core mvc : file is null when you don't select anything. Anyway, the answer is a really clean file upload integration with razor and MVC controller – christophe.chapron Aug 09 '20 at 11:49
  • does not call $('#upload').submit(function. Directly going to controller and also changes the page – Balasubramanian Ramamoorthi May 27 '22 at 18:39
  • @BalasubramanianRamamoorthi in that case you've got something wrong in your HTML or JS. I'd suggest starting a new question about your specific case as this example above is valid and correct. – Rory McCrossan May 27 '22 at 19:38
  • I put $('#upload').submit function is separte js file. After putting in cshtml document ready it worked. – Balasubramanian Ramamoorthi May 29 '22 at 04:17
4

You can't upload files via ajax, you need to use an iFrame or some other trickery to do a full postback. This is mainly due to security concerns.

Here's a decent write-up including a sample project using SWFUpload and ASP.Net MVC by Steve Sanderson. It's the first thing I read getting this working properly with Asp.Net MVC (I was new to MVC at the time as well), hopefully it's as helpful for you.

Nick Craver
  • 623,446
  • 136
  • 1,297
  • 1,155
  • 15
    That's not true; you can send the form data via ajax. – Josh M. Jul 04 '13 at 01:34
  • 9
    @kehrk: With the new FormData and File objects in HTML5, you can indeed upload files via AJAX. Try this: https://developer.mozilla.org/en-US/docs/Using_files_from_web_applications. – jrista Nov 02 '13 at 00:14
1

I have a sample like this on vuejs version: v2.5.2

<form action="url" method="post" enctype="multipart/form-data">
    <div class="col-md-6">
        <input type="file" class="image_0" name="FilesFront" ref="FilesFront" />
    </div>
    <div class="col-md-6">
        <input type="file" class="image_1" name="FilesBack" ref="FilesBack" />
    </div>
</form>
<script>
Vue.component('v-bl-document', {
    template: '#document-item-template',
    props: ['doc'],
    data: function () {
        return {
            document: this.doc
        };
    },
    methods: {
        submit: function () {
            event.preventDefault();

            var data = new FormData();
            var _doc = this.document;
            Object.keys(_doc).forEach(function (key) {
                data.append(key, _doc[key]);
            });
            var _refs = this.$refs;
            Object.keys(_refs).forEach(function (key) {
                data.append(key, _refs[key].files[0]);
            });

            debugger;
            $.ajax({
                type: "POST",
                data: data,
                url: url,
                cache: false,
                contentType: false,
                processData: false,
                success: function (result) {
                    //do something
                },

            });
        }
    }
});
</script>
ddagsan
  • 1,786
  • 18
  • 21
  • bloody hell, I've spent the better part of 2 days wrapping my head around this problem, and here's a solution. Is it possible to modelbind the form though? – Marqueone Aug 23 '19 at 16:54
0

If you posting form using ajax then you can not send image using $.ajax method, you have to use classic xmlHttpobject method for saving image, other alternative of it use submit type instead of button