Rick Strahl's Weblog  

Wind, waves, code and everything in between...
.NET • C# • Markdown • WPF • All Things Web
Contact   •   Articles   •   Products   •   Support   •   Advertise
Sponsored by:
West Wind WebSurge - Rest Client and Http Load Testing for Windows

Using the HTML5 <input type="file" multiple="multiple"> Tag in ASP.NET


:P
On this page:

Per HTML5 spec the <input type="file" /> tag allows for multiple files to be picked from a single File upload button. This is actually a very subtle change that's very useful as it makes it much easier to send multiple files to the server without using complex uploader controls.

Please understand though, that even though you can send multiple files using the <input type="file" /> tag, the process of how those files are sent hasn't really changed - there's still no progress information or other hooks that allow you to automatically make for a nicer upload experience without additional libraries or code. For that you will still need some sort of library (I'll post an example in my next blog post using plUpload). All the new features allow for is to make it easier to select multiple images from disk in one operation. Where you might have required many file upload controls before to upload several files, one File control can potentially do the job.

How it works

To create a file input box that allows with multiple file support you can simply do:

<form method="post" enctype="multipart/form-data">                
  <label>Upload Images:</label>
<input type="file" multiple="multiple" name="File1" id="File1" accept="image/*" /> <hr /> <input type="submit" id="btnUpload" value="Upload Images" /> </form>

Now when the file open dialog pops up - depending on the browser and whether the browser supports it - you can pick multiple files. Here I'm using Firefox using the thumbnail preview I can easily pick images to upload on a form:

MultiFileUpload

Note that I can select multiple images in the dialog all of which get stored in the file textbox. The UI for this can be different in some browsers. For example Chrome displays 3 files selected as text next to the Browse… button when I choose three rather than showing any files in the textbox.

MultipleFilesChosen

Most other browsers display the standard file input box and display the multiple filenames as a comma delimited list in the textbox.

Note that you can also specify the accept attribute in the <input> tag, which specifies a mime-type to specify what type of content to allow.Here I'm only allowing images (image/*) and the browser complies by just showing me image files to display. Likewise I could use text/* for all text formats registered on the machine or text/xml to only show XML files (which would include xml,xst,xsd etc.).

Capturing Files on the Server with ASP.NET

When you upload files to an ASP.NET server there are a couple of things to be aware of. When multiple files are uploaded from a single file control, they are assigned the same name. In other words if I select 3 files to upload on the File1 control shown above I get three file form variables named File1.

This means I can't easily retrieve files by their name:

HttpPostedFileBase file = Request.Files["File1"];

because there will be multiple files for a given name. The above only selects the first file.

Instead you can only reliably retrieve files by their index. Below is an example I use in app to capture a number of images uploaded and store them into a database using a business object and EF 4.2.

for (int i = 0; i < Request.Files.Count; i++)
{
    HttpPostedFileBase file = Request.Files[i];
                    
    if (file.ContentLength == 0)
        continue;

    if (file.ContentLength > App.Configuration.MaxImageUploadSize)
    {
        ErrorDisplay.ShowError("File " + file.FileName +                                " is too large. Max upload size is: " +
                               App.Configuration.MaxImageUploadSize);
        return View("UploadClassic",model);
    }
    
    var image = new ClassifiedsBusiness.Image();
    var ms = new MemoryStream(16498);
    file.InputStream.CopyTo(ms);                
                   
    image.Entered = DateTime.Now;
    image.EntryId = model.Entry.Id;
    image.ContentType = "image/jpeg";
    image.ImageData = ms.ToArray();

    ms.Seek(0, SeekOrigin.Begin);

    // resize image if necessary and turn into jpeg
    Bitmap bmp = Imaging.ResizeImage(ms.ToArray(),                                      App.Configuration.MaxImageWidth, 
App.Configuration.MaxImageHeight); ms.Close(); ms = new MemoryStream(); bmp.Save(ms,ImageFormat.Jpeg); image.ImageData = ms.ToArray(); bmp.Dispose(); ms.Close(); model.Entry.Images.Add(image); }

This works great and also allows you to capture input from multiple input controls if you are dealing with browsers that don't support multiple file selections in the file upload control.

The important thing here is that I iterate over the files by index, rather than using a foreach loop over the Request.Files collection. The files collection returns key name strings, rather than the actual files (who thought that was good idea at Microsoft?), and so that isn't going to work since you end up getting multiple keys with the same name. Instead a plain for loop has to be used to loop over all files.

Another Option in ASP.NET MVC

If you're using ASP.NET MVC you can use the code above as well, but you have yet another option to capture multiple uploaded files by using a parameter for your post action method.

public ActionResult Save(HttpPostedFileBase[] file1)
{
    foreach (var file in file1)
    {
        if (file.ContentLength < 0)
            continue;

        // do something with the file
    }}

Note that in order for this to work you have to specify each posted file variable individually in the parameter list. This works great if you have a single file upload to deal with. You can also pass this in addition to your main model to separate out a ViewModel and a set of uploaded files:

public ActionResult Edit(EntryViewModel model,HttpPostedFileBase[] uploadedFile)

You can also make the uploaded files part of the ViewModel itself - just make sure you use the appropriate naming for the variable name in the HTML document (since there's Html.FileFor() extension).

Browser Support

You knew this was coming, right? The feature is really nice, but unfortunately not supported universally yet. Once again Internet Explorer is the problem: No shipping version of Internet Explorer supports multiple file uploads. IE10 supposedly will, but even IE9 does not. All other major browsers - Chrome, Firefox, Safari and Opera - support multi-file uploads in their latest versions.

So how can you handle this? If you need to provide multiple file uploads you can simply add multiple file selection boxes and let people either select multiple files with a single upload file box or use multiples. Alternately you can do some browser detection and if IE is used simply show the extra file upload boxes. It's not ideal, but either one of these approaches makes life easier for folks that use a decent browser and leaves you with a functional interface for those that don't.

Here's a UI I recently built as an alternate uploader with multiple file upload buttons:

ChromeChosenFiles

I say this is my 'alternate' uploader - for my primary uploader I continue to use an add-in solution. Specifically I use plUpload and I'll discuss how that's implemented in my next post. Although I think that plUpload (and many of the other packaged JavaScript upload solutions) are a better choice especially for large uploads, for simple one file uploads input boxes work well enough. The advantage of this solution is that it's very easy to handle on the server side. Any of the JavaScript controls require special handling for uploads which I'll also discuss in my next post.

Posted in HTML5  ASP.NET  MVC  

The Voices of Reason


 

Jon
March 06, 2012

# re: Using the HTML5 &lt;input type=&quot;file&quot; multiple=&quot;multiple&quot;&gt; Tag in ASP.NET

"You knew this was coming, right?" <- Love it!

magellings
March 06, 2012

# re: Using the HTML5 &lt;input type=&quot;file&quot; multiple=&quot;multiple&quot;&gt; Tag in ASP.NET

I recently needed to implement this and our company internally uses IE 8, so of course needed to provide a shim. Ended up using http://silverlightuploader.codeplex.com/ which works quite well. One thing to also note is these browsers supporting this also support drag and drop on the file input element. I needed to modify the Silverlight control so that it supported drag and drop. End result though is it's really nice UX.

Richard
March 06, 2012

# re: Using the HTML5 &lt;input type=&quot;file&quot; multiple=&quot;multiple&quot;&gt; Tag in ASP.NET

You can sort-of get the files by key, so long as you use the GetKey(index) method:

public static IEnumerable<HttpPostedFile> GetAll(this HttpFileCollection fileCollection, string key)
{
    if (null == fileCollection) throw new ArgumentNullException("fileCollection");
    
    return Enumerable.Range(0, fileCollection.Count)
      .Where(i => string.Equals(key, fileCollection.GetKey(i), StringComparison.InvariantCultureIgnoreCase))
      .Select(fileCollection.Get);
}

Rick Strahl
March 06, 2012

# re: Using the HTML5 &lt;input type=&quot;file&quot; multiple=&quot;multiple&quot;&gt; Tag in ASP.NET

@magellings - I've used the Silverlight Uploader and actually spent quite a bit of time customizing the UI and the backend upload handler. In the end I found though that using Silverlight only solutions is too limiting. I've since switched to plUpload which allows you to specify a host of options from Html5, Flash, JavaScript and even classic HTML 4 based uploads in one place. There are several libs out there that provide this. I'll post my implementation of this in the next post.

@Richard - AH! Yup where there's a will there's a way! :-) Good catch.

Anders Vindberg
April 19, 2012

# re: Using the HTML5 &lt;input type=&quot;file&quot; multiple=&quot;multiple&quot;&gt; Tag in ASP.NET

Another excellent post by you! Im looking forward to your plUpload implementation with MVC. Im in the process of implementing it myself using MVC 4.

Have a good day.
Vindberg.

B Money
July 05, 2012

# re: Using the HTML5 &lt;input type=&quot;file&quot; multiple=&quot;multiple&quot;&gt; Tag in ASP.NET

Great post! Next challenge: rather than displaying the number of files on screen, show the actually file names.

So instead of
Choose Files | 3 files"

Display this:

Choose Files
splash.jpg
sthelens.jpg
sushiwheel.jpg

How would you do this?

Rick Strahl
July 13, 2012

# re: Using the HTML5 &lt;input type=&quot;file&quot; multiple=&quot;multiple&quot;&gt; Tag in ASP.NET

@B Money - you can't unfortunately. The browser determines what gets displayed. You can use third party upload controls like plUpload that use either HTML5's file API or dedicated Flash/Silverlight controls to manage the file uploads, but with HTML native uploads the display can't be customized...

Ali Ahmad
January 23, 2015

# re: Using the HTML5 &lt;input type=&quot;file&quot; multiple=&quot;multiple&quot;&gt; Tag in ASP.NET

I learned many things from your web site, and it is one of them.

If any one want to resize the image, rename the image or upload multiple selection then you can see

http://www.advancesharp.com/blog/1130/image-gallery-in-asp-net-mvc-with-multiple-file-and-size

West Wind  © Rick Strahl, West Wind Technologies, 2005 - 2024