UPDATE - this has now been updated for SL2 RTW.
Many web sites support the ability to upload files (including this one, that's how we get the images up here) and most use HTML's <input type="file"> control to achieve this.
There's one for you to play with right now.
There are a couple of limitations to this control though, including:
- It can only upload one file at a time
- No way to specify the extension filters, e.g. Jpeg File (*.jpg|*.jpeg)
- Can't specify the title of the dialog
- Can only send the data via HTTP POST (which is a very messy business)
This can be a real pain, especially the limitation to one file and this is a particular annoyance when posting a lot of images to this blog.
Fortunately, Silverlight 1.1 contains an OpenFileDialog class that blows away these limitations and I set about creating a Silverlight uploader for theJoyOfCode.com. And here's what it looks like:
Uploader control and HTML button to initiate an upload:
User clicks Upload and selects some files
Upload starts and progress is indicated using an animated progress bar:
If the file already exists on the server, the user is prompted to overwrite:
Finshed! Dialog shows how many files were uploaded:
Most of the code, at least the mechanics, are lifted directly from this File Upload Quickstart
including the use of a .asmx HttpPost reciever on the server. Going forward we'd probably use SOAP (and maybe even WCF with MTOM) as support is added to 1.1, this is one of the features missing from the alpha at the time of writing.
The big differences are that our uploader writes the files to disk on the server, prompts the user to overwrite, supports multiple files and provides progress updates.
Hmmm, well, let's be more truthful about that last statement. Because we're using the BrowserHttpWebRequest object to post the data and this doesn't support updates we report progress by file because we upload one file at a time
If you've read the quickstart
I referenced earlier then you've already got a good idea of what can be done with the OpenFileDialog and for this reason, I think the most interesting bits to discuss here are some of the fudges and workarounds we had to use to get this working in the current 1.1 alpha.
Fudge 1: Using the HtmlTimer to implement Asynchronicity
The HtmlTimer is currently marked obsolete and will probably be replaced in the next refresh of 1.1. However, because I wanted to update the progress bar visuals during the uploading loop I wanted to make the upload asynchronous. And this is easy enough because the System.Threading classes are mostly available (including the ThreadPool) but the main problem is that there is currently no way to marshal a call back to the UI thread. Therefore I decided to change tack and push all the files to be uploaded onto a Queue<>. The HtmlTimer (which always fires on the UI thread, and is therefore not truly asynchronous) could then check this queue and start uploading the next file. The short gap in between the timer ticking will allow the UI to catch up and re-render. It works pretty well and given that the BrowserHttpWebRequest can currently only be invoked from the UI thread, this might be the optimum approach unless this fact changes.
public class JSDialogs
public event EventHandler<MessageEventArgs> Query;
public bool Confirm(string message)
MessageEventArgs mea = new MessageEventArgs(message);
if (Query != null)
// this is wired in as the Silverlight control's onLoad event
function loaded(sender, args, root)
_root = root;
_root.getHost().content.DialogsEntryPoint.Query = jsQuery;
function jsQuery(sender, args)
args.Confirmed = window.confirm(args.Message);
Now whenever we need to prompt the user from C# we can call the JSDialog's Confirm method shown above:
if (_jsDialogs.Confirm("Are you sure you want to do this?"))
There are a few limitations to this little tool, the main one being that if you try to upload a large file (about 5MB+?) then you'll likely get an OutOfMemoryException or the BrowserHttpWebRequest will throw an InvalidOperationException. This is because the whole file is loaded into memory and converted to a Base64 string which is taken from the quickstart mentioned above. Not perfect but it works for now.
I've posted a sample so you can poke around this implementation. Once again, this is SAMPLE CODE
and has not been optimised. It has been written in a short time for a personal project and as such hasn't been subject to a great deal of testing. The content is provided "as is" without warranty of any kind, either expressed or implied, including but not limited to the implied warranties of merchantability and/or fitness for a particular purpose.
Furthermore, it is highly likely that this implementation will no longer work under any future refreshes of 1.1. You may ask why it was the effort given the inevitably short lifetime of the workarounds and fudges I've put in place. For one, I can now upload multiple files to my blog which is a big pain-saver. Also, it was great fun getting to see the limitations and really understand the Silverlight plumbing.
PS - You'll need Visual Studio 2008 (currently in Beta 2) to open the solution.
25 Aug 2007
» Next Post:
WPF for Line of Business Applications
« Previous Post:
Part VI. Creating the Report
Comments are closed for this post.
01 Oct 2007
Thanks~ for your lecture.
I'm Microsoft Visual C# MVP in korea.
At now, I write book about silverlight.
Do you feel when support WCF with MTOM?
01 Oct 2007
I'm afraid it's not just a question of 'When?' but also a question of 'If?'.
There's a lot to squeeze into the tiny 5 megs of space that the silverlight team are working toward. I'm not sure this will make it in.
06 Feb 2008
Any plans to port this to RTM VS08?
07 Feb 2008
Probably not since SL1.1 alpha (which this targets) has no go-live support.
I'll probably revisit it once Silverlight 2.0 (new name for 1.1) goes RTM or a late beta if there's any demand.
08 Nov 2008
The example on the silverlight website is down as is your sample code. Can you repost the code?
29 Dec 2010
29 Dec 2010