Single file upload, using plupload

I'm pretty happy with plupload for all my multi-upload needs. One thing that seems to be missing "out of the box", is the ability to limit the number of queued files. It is possible, with a little event wrangling, to force plupload into allowing only a single upload.

The first thing you need to do is disable plupload's "multi_selection" setting.

var uploader = new plupload.Uploader({
runtimes: 'gears,flash,silverlight,browserplus,html5', multi_selection: false,
...
...
});

An important thing to note here. This doesn't prevent queuing of multiple files, it only prevents multiple SELECTION of files.  There are a few options to preventing queuing of multiple files. The one I've used below works for my needs, but there are other options.

uploader.bind('QueueChanged', function(up) {
if ( up.files.length > 0 && uploader.state != 2) {
uploader.start();
}
});

Basically, this is a bit of a cheat. Whenever we select a file, we check that we're not already uploading and then automatically start the upload. At this point you could then choose to disable the uploader altogether, or in our case, display an icon for the uploaded file and give the user the option to replace it. I've seen other people use the event "FileAdded", but this event looks like it should really be called "BeforeFileAdded", as the newly added file doesn't appear to be added to the "files" collection until after the event has run.

It's worth noting that this method is really only appropriate if you're using your own custom upload interface. Obviously the queuechanged event is triggered when adding AND removing files. Not to mention that our little cheat doesn't actually clear the queue (although there is nothing stopping you doing that).

Using plupload with ASP.NET

I hate file uploaders. The simplest way is always the ugliest, and having anything "nice" requires days of backbreaking labour, and even then you're not even close to being sure it will work across all browsers. It's frustrating to do so much work and then have some users receive seemingly random errors for no apparent reason!

Matt pointed this neat file uploader out to me the other day, plupload. It is very simple and has about a half dozen "fallbacks" for supporting different technologies from Google Gears, Flash and HTML5.

For the most part implementing plupload is a matter of downloading the zip, unzipping and whacking in some sample code. But there IS a catch. Plupload uses BINAY STREAMING, not your bog standard multipart upload. So if you're hoping for a simple drag and drop replacement for your existing code, sorry to disappoint.  But it's not that hard to convert your existing app into a binary stream app!

Of course, there is an easy PHP implementation from the folks that wrote plupload, but I really struggled to find an ASP.NET one. So here's one I wrote based loosely on the PHP version! This is not complete by any stretch (you'd want to handle caching, I/O errors, folder creation etc), but this is the guts of it to save you some research.

Two main things you'll want to take note of.

1. Plupload supports chunks - this is a way to get around upload file size restrictions. Basically, the file can be chopped up and sent as multiple parts, and then put back together again when it arrives. If you look at the requests going to the server, you will see there are actually multiple requests PER FILE. This means we need to stitch the files together when we're done at the other end.

2. Data handling - plupload stores the file name, and chunk info into the querystring, and all the file data is in Request.InputStream...so don't bother trying to work out why Request.Files is empty!

Here is the basics of what you need to implement plupload in asp.net! Easy as! If you're using any other file uploader, change it NOW!

int chunk = Request.QueryString["chunk"] != null ? int.Parse(Request.QueryString["chunk"]) : 0;

//open a file, if our chunk is 1 or more, we should be appending to an existing file, otherwise create a new file FileStream fs = new FileStream(Server.MapPath("/files/" + fileName), chunk == 0 ? FileMode.OpenOrCreate : FileMode.Append); //write our input stream to a buffer

Byte[] buffer = new Byte[Request.InputStream.Length]; Request.InputStream.Read(buffer, 0, buffer.Length);

string fileName = Request.QueryString["name"] != null ? Request.QueryString["name"] : ""//write the buffer to a file.

fs.Write(buffer, 0, buffer.Length);

fs.Close();

Of course, if you're REALLY lazy, they've just recently updated plupload to support multipart uploads...but that's just boring!