Recently I’m trying the Reactive Extensions, an interesting set of extensions that aim to improve the handling of asynchronous programming with an innovative implementation of the observer pattern. These extensions provide some useful methods that solve in an elegant way some recurring problems that everyone have found for sure when calling the network. So, after lot of attempts I found a pattern I will start to use implementing the Data Access facade in my Silverlight applications.
Before discovering the Reactive Extensions (starting from here I will refer to them using the abbreviation RX), I was habit to use a widely adopted pattern that exposes two additional parameters to every method of the Data Access class. For instance, a method made to download a feed from the network may have the following signature and body:
1: public static void DownloadFeed(Uri uri, Action<SyndicationFeed> success, Action<Exception> fail)
5: HttpWebRequest request = HttpWebRequest.CreateHttp(uri);
8: asyncResult =>
12: WebResponse response = request.EndGetResponse(asyncResult);
14: using (StreamReader sReader = new StreamReader(response.GetResponseStream()))
16: using (StringReader reader = new StringReader(sReader.ReadToEnd()))
18: using (XmlReader xReader = XmlReader.Create(reader))
21: () => success(SyndicationFeed.Load(xReader)));
26: catch (Exception ex)
30: }, null);
32: catch (Exception ex)
Using the HttpWebRequest made the code more complicated but the WebClient does not makes significant changes to the way the network call works. This pattern is interesting because using some lambda expression the resulting code remain compact. The drawback is that every method has two more parameters so the code is hardest to be understood.
The RX framework contains two methods that are useful to handle a network connection; Observable.FromAsyncPattern is really useful if you want to use an HttpWebRequest because it can automatically handle the Begin and End parts of the asynchronous pattern. On the other side, Observable.FromEvent can attach an event and gracefully detach when it is not reqired anymore; it is the case of the WebClient class tha expose a DownloadStringCompleted event. So we start handling the async pattern of an HttpWebRequest:
1: public static IObservable<SyndicationFeed> DownloadFeedWebRequest(Uri uri)
3: HttpWebRequest request = HttpWebRequest.CreateHttp(uri);
5: return Observable.FromAsyncPattern<WebResponse>(request.BeginGetResponse, request.EndGetResponse)
These few lines does the trick: The Observable.FromAsyncPattern method encapsulates BeginGetResponse and EndGetResponse. The resulting object is a synchronous representation of the async pattern. The Invoke method call the service then two methods I wrote read the resulting stream and convert the string to a syndicationfeed. Finally, with the ObserveOnDispatcher method I marshal the thread to the user interface using the dispatcher.
The return value is an IObservable<SyndicationFeed> instance that enable the caller to listen for the completion of the operation. The way the method is called is very similar to my previous patter but the method now has only the needed parameters:
1: DataSource.DownloadFeedWebRequest(new Uri("http://api.twitter.com/1/statuses/public_timeline.atom"))
3: r =>
5: feed.ItemsSource = r.Items;
6: }, HandleExceptions);
The Subscribe method I use here exposes two callbacks, one provides the result of the method and the other is called when an exception occur. If you prefer to use the WebClient you can use the Observable.FromEvent method the complete the same operation.
1: public static IObservable<SyndicationFeed> DownloadFeedWebClient(Uri uri)
3: WebClient client = new WebClient();
5: IObservable<SyndicationFeed> result = Observable.FromEvent<DownloadStringCompletedEventHandler, DownloadStringCompletedEventArgs>(
6: ev => new DownloadStringCompletedEventHandler(ev),
7: ev => client.DownloadStringCompleted += ev,
8: ev => client.DownloadStringCompleted -= ev)
9: .Select(o => o.EventArgs.Result)
14: return result;
In the method we have to specify the attach and detach actions. These action will be called by the RX when the Subscribe method is complete; Here we do not need to call the ReadToEnd method because the WebClient returns directly a string and also we do not have to marshal to the UI Thread because the WebClient already does the trick. The select method convert the resulting EventArgs to the value expected from the ConvertToFeed.
I’m very intersted in your opinion on this example. My feel is that the code is more reusable, and compact, but if someone have a suggestion to improve the method pleare