One of the things people have been asking for, particularly since AJAX became popular, is being able to asynchronously upload files. Silverlight 1.1 contains the building blocks to make this possible. I've written an ASP.NET control to demonstrate this feature as an end-to-end scenario. Please note that this feature is just a prototype. As you will see in the source code comments, there is plenty of room for improvement and polishing.
To see the results, go to the AsyncFileUpload demo. (As you can see in its codebehind, there's currently a limit of a bit less than 1mb for the total file upload size.) You can also check out the source-code of this control.
OpenFileDialog
The first building block that I use in this control is the new OpenFileDialog (OFD). This dialog will return read-only streams to one or more files on the client. You can read from those streams on the client. Additionally you can also define filters, set a title, etc.
1
2
3
4
5
6
7
8
9
10
11
12
13
|
OpenFileDialog ofd = new OpenFileDialog();
ofd.Title = "Select a file...";
ofd.Filter = "Word Documents|*.doc;*.txt|All Files|*.*";
ofd.EnableMultipleSelection = true;
if (ofd.ShowDialog() == DialogResult.OK) {
foreach (FileDialogFileInfo file in ofd.SelectedFiles) {
using (StreamReader reader = file.OpenRead()) {
string fileName = file.Name;
string contents = reader.ReadToEnd();
// ...
}
}
}
|
BrowserHttpRequest
The next block is BrowserHttpWebRequest. This is an abstraction of the browser's XMLHttpRequest object and uses the exact same semantics. In my case I use this object to upload chunks of the file to the server. (Specifically, to a server-side ASP.NET handler which will save/append the chunk.) Since binary data is currently not supported in all browsers, we base64 encode the data before sending it to the server.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
// NOTE: In the future we'd like to hide BrowserHttpRequest, so you only need to
// use (and know about) HttpWebRequest. That should make it easier to port code
// between different environments (Silverlight/desktop).
HttpWebRequest request = new BrowserHttpRequest();
request.Method = "POST";
StreamWriter writer = new StreamWriter(request.GetRequestStream());
writer.Write(...);
request.BeginGetResponse(OnResponse, request);
...
void OnResponse(IAsyncResult asyncResult) {
HttpWebRequest request = (HttpWebRequest)asyncResult.AsyncState;
HttpWebResponse response = request.EndGetResponse(asyncResult);
using (StreamReader reader = new StreamReader(response.GetResponseStream())) {
// response.StatusCode, ...
string responseText = reader.ReadToEnd();
}
}
|
Scriptability
Another feature we're using is [Scriptable]. This attribute can be applied on types/members that can be accessed from JavaScript. This is useful in case you want to extend the browser programming framework for JS developers. In my case I use this to expose the ProgressChanged event. You can handle this event from JavaScript to do something more complicated than a simple progress bar and/or message.
1
2
3
4
5
6
7
8
9
10
11
12
13
|
[Scriptable]
public class AsyncFileUpload : Canvas {
void OnCanvasLoaded(object sender, EventArgs e) {
// We need to explicitly expose object instances to JavaScript.
WebApplication.Current.RegisterScriptableObject("uploader", this);
}
[Scriptable]
public event EventHandler<ProgressChangedEventArgs> ProgressChanged;
....
}
|
1
2
3
4
5
6
|
var control = document.getElementById('AgControl1');
var uploader = control.Content.uploader;
uploader.ProgressChanged = function(sender, args) {
// Sender is currently always null.
// Use args.Progress here...
}
|
Currently our scripting support is limited to primitive types and HTML/JS objects only. This means you can't (yet) return arbitrary managed objects to JS.
In closing...
This is just a quick write-up on some of the features you will find in Silverlight. I hope with this quick and dirty post I have gathered some interest in the programming API portion of Silverlight. I hope you'll realize that Silverlight can be used to do some visually very compelling things, but is not at all limited to that. Thoughts?