A little less than a year ago I wrote about an AsyncFileUpload component for Silverlight/ASP.NET. Several things have happened since then, so I decided to rewrite it and address some of the limitations it had along the way. To make sure we’re on the same page, let me outline the goals of this proof-of-concept:
- Demonstrate how OpenFileDialog and HttpWebRequest can be used to upload (large) files.
- Show how isolated storage can be used to enable file resumes (even across browsers on the same machine).
- Share some experimental object model to simplify ASP.NET/Silverlight component development.
The only real non-goal is building a file upload component of production-quality.
The result
There are a few different demos you can take a look at:
- AsyncFileUpload with the default template (pure HTML visualization);
- AsyncFileUpload with a custom template (includes two Silverlight visualizers);
- AsyncFileUpload used from JavaScript. Although this demo still uses ASP.NET, you could easily do the same thing from other languages/frameworks/web-servers as well.
You can also download the source code for the actual library behind all of this.
Uploading large files
Silverlight 2’s HttpWebRequest buffers the request data in memory entirely, because the underlying API it uses (provided by the browser) doesn’t support streaming. This means that – at least at the time of writing – you can’t just upload large files.
We can work around this by uploading files in chunks. It does mean we need some special handling on the server, but a basic implementation requires little effort. We just need to make sure we send some meta-data with each chunk, such that the server knows where a chunk is supposed to go. There is some overhead involved here, but we can make up for this by showing accurate and visual feedback.
By sending chunks to the server, we get support for resumes almost for free. All we need to do is keep track of some information, such as something that identifies a file and the location of the next chunk we need to send. When we store this information in isolated storage, we can use it from every browser on the user’s machine. This means you can resume uploading a file in any of the installed browsers, even if you uploaded part of the file in a different browser.
While we’re uploading chunks to the server, we know exactly how much we’ve progressed and how much there is left. We can also easily find out how fast we’re uploading. This data can be used to give feedback to the user about the progress, speed, anticipated time left, and so forth.
On the server we need to know a few things per chunk:
- Something that identifies the file;
- Something that identifies the user;
- The chunk’s location;
- The actual data.
When we have this information, we can process each chunk fairly easily. We could additionally return a checksum of the file and verify on the client that the server processed the right data. If it didn’t, the client could try resending the chunk.
After the client is done uploading, it could submit a form to the server. On the server you would again need something that identifies the user (such as a session ID) to find out what exactly has been uploaded.
ASP.NET/Silverlight component development
I will go over this in a separate post, probably tomorrow.