How do I handle HTML5 Multiple File uploads in ASP.NET MVC?

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.

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

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.

Method 2

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.

@using School.ViewModels
@model UserProfileViewModel


<form enctype="multipart/form-data">
<input id="username"name="username" type="text" />
<input name="Myfiles" type="file" multiple="multiple" />
<input type="button" value="Upload" />
</form>

UserProfileViewModel.cs

namespace School.ViewModels
{
    public class UserProfileViewModel
    {
        public long Username { get; set; }

        public List<HttpPostedFileBase> Myfiles { get; set; }
    }
}

UserProfilePicturesController.cs

public ActionResult Create([Bind(Include="Username,Myfilese")] UserprofileViewModel userprofileViewModel)
{
     var files = userprofileViewModel.Myfiles;
     foreach(HttpPostedFileBase file in files)
     {
         //do something here
     }
}


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x