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.
What does work, is the following, from the blog of the always dependable and dynamically haired Rick Strahl
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.
In my case what worked for me was binding all my files to a ViewModel field. ViewModel would be the model the I use for my front end.
UserProfileViewModel.cs
UserProfilePicturesController.cs