views:

811

answers:

4

I have a WCF services that has to return some data sets that can be as large as 10mb or more, I want some visual feedback for the user on progress, is there a way to track the download progress?

My client is Silverlight 3 and ultimately I would like to be able to bind a progress bar to this; any ideas?

EDIT: After the bounty SO automatically selected the answer with upvotes as the correct answer when this is not the case.

+4  A: 

There is an example of this on the code project, see:

http://www.codeproject.com/KB/WCF/WCF%5FFileTransfer%5FProgress.aspx

Shiraz Bhaiji
+1 good and very interesting link, thanks!
marc_s
I've tried this and it does work as advertised. Not sure if the Silverlight business will add some additional complexity, but the basic theory is sound.
Anderson Imes
There are two main things that you need to watch out for when transfering these ideas to silverlight. 1. Silverlight does not support all WCF bindings. 2. Silverlight is a subset of the dotnet framework so something may be missing.
Shiraz Bhaiji
Silverlight does not support transferMode="Streamed" http://forums.silverlight.net/forums/t/119340.aspx
Mike Blandford
+1  A: 

If you have one giant WCF call, then you only have two states, everything or nothing. Also, WCF has a maximum transaction size, so returning a large dataset runs the risks of going over this limit.

In order to solve these problems in my projects, I split the one big request into many smaller requests. I then check how many responses I have vs. original requests to get an indication of progress.

Edit: added better explanation.

Jacob Adams
This is true for the default TransferMode (Buffered) - you get the message in whole, and there's nothing happening in between until you have everything. But using TransferMode=Streaming changes all that - you have a stream now, and you can get notified of progress during reading from a stream.
marc_s
Maybe the explanation isn't completely correct, but I do like this approach and it could very well be something I'd use as this does abstract the plumbing involved in doing streamed responses. Also it may be useful in more then one scenario (some form of paging, for example).
Jonathan van de Veen
A: 

The CodeProject article may be tricky to get working with Silverlight since Silverlight only has access to the BasicHttpBinding -- although it looks like BasicHttpBinding has a TransferMode="Streamed" so perhaps it is possible -- I don't know.

If you can get it to return a Stream, that seems like it would be the best approach.

Still, I thought that I would put forward a random "other" approach.

Perhaps you could serialize the data into a file and use the WebClient to download it. So basically, you would have a WS.GetData() which would save a file on the server and return its filename -- then the Silverlight app would use WebClient to download it (which has a DownloadProgressChanged event).

I know it's not what you're looking for -- just an idea...

Timothy Lee Russell
A: 

EDIT: I answered this thinking you wanted a silverlight uploader, but it actually looks like you want a silverlight downloader. You can do the same thing I suggested for the uploader except use HTTP GET, or Binary WCF, or Sockets.

I have written a Silverlight 2 uploader with a progress bar and I modeled it after this one. It uses HTTP POST to sent the file to the server one piece at a time. The tricky part is that the bigger your POST, the faster the file will be uploaded, but your progress bar only gets updated once per POST. So I wrote an algorithm that dynamically tries to find the biggest POST size that takes less than a second.

If you want to use WCF instead of HTTP POST, that's probably better because Silverlight 3 now supports binary message encoding:

<customBinding> <binding name="MyBinaryBinding" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647"> <binaryMessageEncoding /> <httpTransport /> </binding> </customBinding>

OR you could write a sockets implementation - Silverlight does support this but it can be a little tricky to setup and requires your server to have a port in the range 4502-4532 open, and port 943 open for a policy file.

Mike Blandford