Silverlight does not support synchronous web requests. For this reason, I wrote Simple Asynchronous Operation Runner . One goal is to be able to write code as if it were synchronous, and then modify it to work with the runner code.
First, get a small piece of code for AsyncOperationService from the first part and add it to your project (don’t worry if you find that the article is a little heavy, which is not important for its actual use).
Using the code that you have already indicated as a “synchronous template”, we see that we need a couple of AsyncOperation implementations for GetRequestStream and GetResponseStream , so we will write them by adding them to the project:
public static class WebRequestAsyncOps { public static AsyncOperation GetRequestStreamOp(this WebRequest request, Action<Stream> returnResult) { return (completed) => { request.BeginGetRequestStream((result) => { try { returnResult(request.EndGetRequestStream(result)); completed(null); } catch (Exception err) { completed(err); } }, null); }; } public static AsyncOperation GetResponseOp(this WebRequest request, Action<WebResponse> returnResult) { return (completed) => { request.BeginGetResponse((result) => { try { returnResult(request.EndGetResponse(result)); completed(null); } catch (Exception err) { completed(err); } }, null); }; } }
Now, if you are uploading a file, you will probably want to report the progress in the user interface, so I suggest you have this AsyncOperation on hand (type in the existing AsyncOperationService class): -
public static AsyncOperation SwitchToUIThread() { return (completed => Deployment.Current.Dispatcher.BeginInvoke(() => completed(null))); }
Now we can create an asynchronous version of your code: -
IEnumerable<AsyncOperation> Chunker(Action<double> reportProgress) { double progress = 0.0; Chunk chunk = new Chunk(); // Setup first chunk; while (chunk != null) { Stream outStream = null; HttpWebRequest req = ... yield return req.GetRequestStreamOp(s => outStream = s); // Do stuff to and then close outStream WebResponse response = null; yield return req.GetResponseOp(r => response = r); // Do stuff with response throw error is need be. // Increment progress value as necessary. yield return AsyncOperationService.SwitchToUIThread(); reportProgress(progress); chunk = null; if (moreNeeded) { chunk = new Chunk(); // Set up next chunk; } } }
Finally, you just need to run it and handle any error: -
Chunker.Run((err) => { if (err == null) { // We're done } else { // Oops something bad happened. } });