Monday 3 August 2009

Creating Synchronous Web Requests in Silverlight

A word of warning out there to all you budding Silverlight developers. Don't try and do something like this...
private class RequestState
{
public HttpWebRequest Resquest { get; set; }
public HttpWebResponse Response { get; set; }
public ManualResetEvent ResetEvent { get; set; }
}

public static IEnumerable<string> GetFolders(string uri)
{
var requestState = new RequestState();
requestState.Resquest = (HttpWebRequest)WebRequestCreator.ClientHttp.Create(new Uri(uri, UriKind.Absolute));
requestState.ResetEvent = new ManualResetEvent(false);
requestState.Resquest.BeginGetResponse(GetFoldersCallback, requestState);
requestState.ResetEvent.WaitOne();
return ProcessFolderResponse(requestState.Response);
}

private static void GetFoldersCallback(IAsyncResult result)
{
var requestState = (RequestState)result.AsyncState;
requestState.Response = (HttpWebResponse)requestState.Resquest.EndGetResponse(result);
requestState.ResetEvent.Set();
}
It won't work and will just hang. Even though the exact same code will work a treat in a non-Silverlight environment. I tried all sorts to get this to work and pulled my hair out for hours. The reason for this is that the Silverlight runtime gets upset if the main thread gets blocked. So you'll just have to stick with the asynchronous methods and callbacks.

The best I could do was to ask for my own callback and wrap that in a call to Dispatcher.BeginInvoke.
public static void GetFolders(Dispatcher dispatcher, string uri, Action<IEnumerable<string>> folderAction)
{
var request = (HttpWebRequest)WebRequestCreator.ClientHttp.Create(new Uri(uri, UriKind.Absolute));
request.BeginGetResponse(ar =>
{
var response = request.EndGetResponse(ar);
var folders = ProcessFolderResponse(response);
dispatcher.BeginInvoke(() => folderAction(folders));
}, null);
}

No comments:

Post a Comment