How do I handle HTML5 Multiple File uploads in ASP.NET MVC?
ajax, asp.net, file-upload, html, jquery
Solution
What does work, is the following, from the blog of the always dependable and dynamically haired Rick Strahl
public string Upload()
{
for (int i = 0; i < Request.Files.Count; i++)
{
var file = Request.Files[i];
}
}
The reason behind this is that the collection of files passed to `Request.Files` all have the same name, because they come from a singular file upload dialog.
the server side method is passed a single object containing the files, and for some reason Request.Files is the only way to get at it.
Hopefully I've saved someone a bit of headache by adding this in.
Problem
I found the following great thread with an explanation of how to do file uploads through AJAX/Jquery using the new HTML5 FormData API Here's a slightly updated version of that code, with the newer JQuery 1.8+ syntax ``` $(':button').click(function(){ var formData = new FormData($('form')[0]); $.ajax({ url: '/Upload', //my ASP.NET MVC method type: 'POST', // handle the progress report xhr: function() { // Custom XMLHttpRequest var myXhr = $.ajaxSettings.xhr(); if(myXhr.upload){ // Check if upload property exists myXhr.upload.addEventListener('progress',progressHandlingFunction, false); // For handling the progress of the upload } return myXhr; }, // Form data data: formData, //Options to tell jQuery not to process data or worry about content-type. cache: false, contentType: false, processData: false }) .done(function(){ alert("success"); }) .fail(function(){ alert("error"); }); }); function progressHandlingFunction(e){ if(e.lengthComputable){ $('progress').attr({value:e.loaded,max:e.total}); } } ``` and here's the form ``` <form enctype="multipart/form-data"> <input name="file" type="file" /> <input type="button" value="Upload" /> </form> <progress></progress> ``` On the server side, we have something like this. ``` [HttpPost] public string Upload(HttpPostedFileBase file) { // do something with file return "you uploaded a file called " + file.FileName; } ``` This works great. UNTIL you decide to use the "multiple" attribute on the file dialog, and send multiple files. ``` <form enctype="multipart/form-data"> <input name="file" type="file" multiple="multiple" /> <input type="button" value="Upload" /> </form> <progress></progress> ``` You'll find various pages online suggesting the following solutions ``` public string Upload(IEnumerable<HttpPostedFileBase> files) { foreach(var file in files) ... } ``` Oops. Doesn't work ``` public string Upload(List<HttpPostedFileBase> files) { foreach(var file in files) ... } ``` Nope. Doesn't work. ``` public string Upload(IEnumerable files) { foreach(var file in files) ... } ``` Doesn't even compile ``` public string Upload(HttpPostedFileBase[] files) { foreach(HttpPostedFileBase file in files) ... } ``` Guess what? Doesn't work. Lets try dealing with Request.Files instead. Good old reliable Request.Files. Never fails. ``` public string Upload() { foreach (HttpPostedFileBase uf in Request.Files) ... } ``` Spoiler alert: It Doesn't work. Aha. Got it! I'll iterate over the keys in Request.Files instead. ``` public string Upload() { foreach(var key in Request.Files.AllKeys) { var file = Request.Files[key]; } } ``` Yet again, it doesn't work.