Silverlight does not support synchronous web requests. For this reason I wrote the Simple Asynchronous Operation Runner. One of the objectives is to be able to write code as if it were synchronous then modify it to work with the runner code.
First get the small chunk of code for the AsyncOperationService
from part 1 and add it to your project (don't worry if you find the article a little heavy its not important to actually using it).
Using the code you already provided as "synchronous template" we can see we need a couple of AsyncOperation
implementations for GetRequestStream
and GetResponseStream
so we'll write those an add them to the project as well:-
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 chunking a file upload you'll probably want to report progress into the UI so I would suggest you have this AsyncOperation
on hand as well (inject in to the existing AsyncOperationService class):-
public static AsyncOperation SwitchToUIThread()
{
return (completed => Deployment.Current.Dispatcher.BeginInvoke(() => completed(null)));
}
Now we can creare 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.
}
});