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

Silverlight and Threading


:P
On this page:

I've spent the better part of the last couple of days playing around with Silverlight 1.1 and it's been an interesting experience. It's both exciting and frustrating at the same time - exciting because it's incredibly nice to see .NET code running in the browser and being able to debug it. Frustrating because of the limited functionality that the Silverlight runtime has in terms of UI support specfically lack of controls and lack of a number of UI semantics. I'll post a more general post of impressions later this weekend.

But here is a more specific problem that I haven't found a solution for, but makes an interesting discussion of some of the things I hope you will be able to do with Silverlight.

A lot of focus has gone towards the visual and media aspects of Silverlight, but I think maybe the coolest feature of Silverlight is the fact that it brings the .NET platform and its richness to the browser. There are lots of ways to interact between HTML and the .NET runtime in this scenario.

As I was playing around I had this idea of building a small file upload control that can do in page uploads. I actually could use a more flexible way to handle file uploads to my photo album and so I set out with this small project.

And it's surprisingly easy to build such a thing. Silverlight includes an open file dialog that allows the user to select one or more files (which are exposed only as open file streams just like isolated storage) and so I pick up these files and store them in a List. The optional UI can then display the list of selected files. You can then call another method called UploadFiles to send the files to the server using the BrowserHttpWebRequest object which optionally can display a UI to display progress or alternately fire a StatusMessage event that can be handled by the browser app.

This is a very cool concept if you think about it: You can have an HTML page that interacts with a .NET component and the code used in that component can be fairly full featured. Silverlight is surprisingly feature-ful considering its small footprint... works great except the code runs on the main thread so while the upload is running the UI is frozen - not optimal but still an improvement from a UI perspective (it's much easier to pick files with the file dialog and do multiple selections for example then display the picked file list - big UI step up from a File control in HTML).

Anyway, creating the control's logic - minus the UI - plus the browser interop was surprisingly easy and took a couple of hours while fumbling with the documentation and figuring out the proper way to hook up the control from the HTML and expose properties and events (don't forget the [Scriptable] attribute on EVERYTHING that's visible to the browser. It's extremely satisfying to see the code work and interacting between the browser and the Silverlight control, using events for communication.

That part was easy. The tough part though is the UI. Silverlight is very rich but at the very same time extremely limited when compared to full WPF. I've been reading up and not doing much with WPF, so I feel somewhat comfortable with the concepts, but Silverlight is missing a ton of important features of WPF. The most annoying ones are lack of easy clipping support, lack of autosize support (no Auto sizing) and support for only one top level panel - Canvas. There are no StackPanels, WrapPanels or DockPanels for example. Also text functions are VERY limited. You basically have TextBlock and there's not even any support for text alignment. Without alignment and clipping it's pretty tough to build even simple display layout if the layout is not fixed sized. Some of these may seem like nitpicking but without better panel and flow support creating UI logic or even a fancy text display is not exactly trivial. For example, since there are no controls at all if you want to display data that overflows you have to create your own scrollers. Eh - no thanks I'll wait until there's better control support <s>...

So after spending a few hours playing around with various samples and trying to build a nice looking UI for this control I decided to bag it and just expose this control as a component.

BrowserHttpWebRequest on non-UI Threads

One important aspect of a control that does uploads would have to be multi-threading and one of the things that is awesome in Silverlight is that there's full threading support. You can spin up new threads and start doing processing on these threads. So naively I assumed that the threading would just work by moving the HTTP processing off to a separate thread then process the request synchronously on the separate thread.

Ha - it should be so easy. Silverlight uses the XmlHttp object of the browser and so although the .NET interface looks more like HttpWebRequest, it's really tied to the XHR object in the browser and all of its limitations. The main issue here is that XHR HAS TO run on the main UI thread so you can't fire it off syncrhonously off a new thread that you've spun up. So much for that idea. The only way to make this work is to use the Aysnc model which as it turns out is actually more obtuse than using XHR in the browser even - especially if you need to POST data to the server. I'll leave that for tomorrow <s>...

Multithreading and UI Access

But before I ran into this problem I had to deal with another: As soon as I started hooking together the threaded upload code with the user interface I hit the wall. With the limited visual UI I have built I wanted to update at least a status message and a simply progress bar simulation. Unfortunately I couldn't figure out a way to do this from the worker thread. Like in WinForms Silverlight doesn't allow updating of UI components from anything but the main thread so updating things like the text of the Textblock for thet file progress message didn't work. Unlike WinForms however, Silverlight does not (yet) have any way to marshal the thread as far as I can tell. There's Control.Invoke/BeginInvoke.

I thought - ah the UI is not that important anyway, I'll just fire the events back to the browser. But that also failed due to the UI thread limitation. Basically anything that goes back to the browser - presumably over COM at least in IE requires that it runs on the main UI thread. Same issue there - so no events from different threads work either.

This is a pretty big bummer actually. The XHR issue is understandable and there is a workaround by using the async event (BeginGetRequestStream() BeginGetResponse()), but the UI issue apparently has no workaround currently.

No doubt there will be a solution to this in the future but this limits what you can realistically do with threading currently pretty severely since there's no way to fire events directly back into the browser from a separate thread. For some things I'm thinking about this would be a crucial feature.

Exciting and Frustrating

The possibilities are definitely there but it's still very early in this product cycle. Actually, I think it's pretty amazing how stable all of this stuff is given its Alpha status. Even with the funky threading code and my UI awkardness I didn't once crash Silverlight or IE all day today. The code didn't blow up and performance of this stuff is excellent. Before I started with Silverlight I had visions of my previous work with Windows Mobile and the nightmare that entailed, but this development experience is nothing like this and it's pretty seamless. You can create two projects - one Web project to test with and one for the Silverlight library to create and from there it's as simple as debugging your code like you normally would. It just works as you would expect.

Good things will come of this!

Posted in Silverlight  

The Voices of Reason


 

Wilco Bauwer
May 05, 2007

# re: Silverlight and Threading

> The only way to make this work is to use the Aysnc model which as it turns out is actually more obtuse than using XHR in the browser even - especially if you need to POST data to the server.

Hm? :) This is what I'm doing in my AsyncFileUpload demo (http://www.wilcob.com/Wilco/Silverlight/silverlight_asyncfileupload.aspx), and that Works Fine For Me (tm).

As for threading in general... Although this stuff is exposed, I am personally somewhat skeptical about the ability to create new threads. Imagine going to an arbitrary website which suddenly starts 10 threads to do who knows what... I suspect my browsing experience would degrade pretty quickly if a bunch of apps would be aggressively working with a bunch of threads. I think what we really need is a higher-level primitive, like BackgroundWorker. With such a primitive you could do your work on a non-UI thread. The BW could raise progress/completion events on the UI thread and you wouldn't have to bother marshalling anything.

Rick Strahl
May 05, 2007

# re: Silverlight and Threading

Wilco, damn I missed that - that would have saved a little time <s>...

Yeah, doing this using async calls works, but you get none of the richness you get with the 'full' HttpWebRequest due to the limitations of XHR. If you think of uploads running using XHR then the advantage of using Silverlight disappears.

Take my example here. What I wanted to accomplish is have the control upload a group of files by creating a custom POST multi-part POST buffer and provide progress information. Well, there's no progress indication - you just get the async complete callback. IOW, you actually get LESS functionality than using XHR because you don't even get the intermediate calls much less progress information.

Uploads of various kinds is one scenario that comes up quite frequently in applications I've built over the years and for a number of customers of one of my tools and separate Socket/HTTP support certainly would provide solutions to these problems.

As to the threading issues - sure there's always the chance that the functionality will be abused. But I doubt just because it's there people will start putting all sorts of code onto threads when there's no need.

But multi-threading for background communications with the server are really where I think the threading could be very beneficial! This background file uploader being a good example (except that it can't be done as richly as I would have hoped <s>).

Wilco Bauwer
May 05, 2007

# re: Silverlight and Threading

Ah, I see what you mean now. The trick I use to deal with progress notifications is to actually read chunks of bytes from the selected files and fire a request for each chunk. This has several advantages, such as the ability to allow pause/resume, actually stream the file (rather than having to read the client file completely into memory), etc.

It's a good point though that we hide the intermediate events that are raised (readystates other than 4). Hmm. Point noted. :)

Sockets is something several people have showed interest in. I'd love to see it myself as well. The more feedback, the higher priority this will be given.

As for separate HTTP support - I'm not exactly sure what you specifically mean by this. Are you after the ability to do cross-domain requests? Or is there something else that the current BrowserHttpWebRequest does not provide?

Regarding threading... What do you think of a higher-level concept like BackgroundWorker? Would that work? In that case it could actually use a thread pool under the hood, potentially limited to a low number of threads to make sure applications can't (unintentionally) affect the browsing experience.

Rick Strahl
May 05, 2007

# re: Silverlight and Threading

<g> yeah, done the chunks before - it's no fun on the server side... This becomes very brittle too - if a chunk gets lost or doesn't make it/time out you end up having to deal with the partial data on the server.

I think there are a many scenarios for sending data from the client to server via HTTP and XHR doesn't provide much in the way of feedback information. If we'll end up building rich data driven application on the client having EASY access to data on the server be it through high level abstractions (via Web Services, Data Services) or by lower level means should be well taken care of and as easy as possible. I would even go as far as saying there should be a WebClient class that has abstractions for PostData encoding (ie. FormVars, Multipart, Uploads etc.) although that can be built by ourselves. Data access is a crucial piece and it should be as easy as possible.

This will also make it easier for tool developers especially to build rich connectivity with improved feedback. We can do most of this stuff today in HTML but the problem is the feedback that's missing and I don't think that XHR is rich enough to provide that info.

With XHR you get onReadyStateChange, but there's no info in there on where in the process the request is at. How much data's been downloaded or uploaded as is the case here. With the full HttpWebRequest you have the abillity to chunk the data as part of the request just by feeding the streams in smaller chunks. The modularity makes this workable and easy on top of it. Couple that with running on a background thread (or pool thread) and you have somthing that's much easier to work with than an async callback that doen't give you all the information you need.

For myself, whenever possible I try to keep actual operations synchronous for logical simplicity and then use threads/delegates for running the synch process in the background as this is usually easier to deal with than async patterns IMHO because you get a access to a full API as oposed to whatever the Async calls publish.

As to BackgroundWorker - that would be great, but even a simpler way that can help resync to the UI thread (ie. ala Control.Invoke/BeginInvoke in WinForms) would do the trick.

Using a ThreadPool with a limit on threads is probably a good idea. Async delegates or ThreadPool threads are fine, or limiting the number of threads that can be created via Thread.Start() also might be Ok. I wouldn't foresee people creating huge numbers of threads, but having a couple of background threads perform work can certainly be a big help in some scenarios. I'm not sure if thread overload is really a big deal given the horse power we have on the client these days and given that threading is still going to be a specialty scenario in most cases.

Wilco Bauwer
May 05, 2007

# re: Silverlight and Threading

Yes, there are some caveats you have to deal with when manually sending chunks to ensure the integrity of uploaded files. I understand this is unacceptable for people to manually have to send chunks and transfer data at such a low level. I think one of the things we could consider is providing abstractions on top of BrowserHttpWebRequest that takes care of this. Developers would then not have to worry about integrity, we could enable pause/resume, progress, allow 'streaming', etc. Something like this would have to be backed up by a tightly coupled server-side mechanism though, such as an ASP.NET IHttpHandler. Tradeoffs...

Alternatively we could consider abstracting the OS HTTP stack rather than the browser HTTP stack. This does have some implications though, including security implications. To make sure requests are running in the same security context, we'd have to enable cookies in those requests. (In the desktop framework you have to explicitly deal with cookies yourself. In the browser though you expect this to be taken care of automatically, in my opinion.) We could only do this for requests back to the origin server though, because otherwise you'd have a XSS hole. One of the other implications is limiting the number of outstanding requests (which is 2 in IE). It's stuff like that which makes it a fairly complicated and risky feature.

# DotNetSlackers: Silverlight and Threading


Michael Sync
April 09, 2008

# re: Silverlight and Threading

UI marshalling .. Thanks to martin_hughes...

private delegate void dUpdate();
private void update()
{
if (this.Dispatcher.CheckAccess())
{
//Work to be done goes here

}
else
{
//Invoke the call on to the UI thread
this.Dispatcher.BeginInvoke(new dUpdate(this.update), new object[] {});
}

}

pravallika
July 08, 2008

# re: Silverlight and Threading

how we can over come the cross thread access exception in silver light by using threads?

Rick
September 28, 2008

# re: Silverlight and Threading

Folks, i want to call a function after every x minutes so that I can clear the objects from the custom build cache.

Any way around to run thread and sleep?

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