Login or Sign Up to become a member!
LessThanDot Sit Logo

LessThanDot

Desktop Developer

Less Than Dot is a community of passionate IT professionals and enthusiasts dedicated to sharing technical knowledge, experience, and assistance. Inside you will find reference materials, interesting technical discussions, and expert tips and commentary. Once you register for an account you will have immediate access to the forums and all past articles and commentaries.

LTD Social Sitings

Lessthandot twitter Lessthandot Linkedin Lessthandot friendfeed Lessthandot facebook Lessthandot rss

Note: Watch for social icons on posts by your favorite authors to follow their postings on these and other social sites.

Your profile

    Search

    XML Feeds

    Google Ads

    « Exploring Reactive Extensions - Adding a Dash of LinqUnit Testing Costs Too Much - Twice The Code = Value? »
    comments

    A while ago, a coworker (Jon) showed us a presentation over lunch that he had given at the local alt.net user group on the Reactive Extensions for .NET. I was pretty unfamiliar with the subject, but once I got the lowdown from this presentation it was quite clear that this was something I'd need to explore. At the most basic level, the reactive extensions are about setting up your objects to react to something they are subscribed to. In the presentation, he used an analogy of a reversed, or push-based IEnumerable, and I like that a lot. There is a ton of cool stuff in this library that I hope to get into later, but it all hinges on that idea.

    I've only recently been getting back into windows desktop development (coming from a more web-centric environment) so it is possible that I'm overreacting to the pain of dealing with events in windows forms, but this paradigm really appeals to me. It gives you a way to call methods on your observers from the object they are observing, through a standard set of interfaces. The simpler parts are possible using the normal event mechanisms found in .net, but keeping the interaction limited to a standard set of interfaces (and explicitly calling the code from a central location) feels much simpler to me.

    Interface Overview

    The two interfaces we need are remarkably simple, but very powerful. The generic IObservable interface only has one method, Subscribe, taking an IObserver of the same type. This allows the observers to register with the object they need to observe, in order to receive updates. The IObserver interface contains three methods, OnNext(T), OnError and OnComplete. I think these are all pretty straightforward. OnNext and OnComplete allow you to process items and figure out when processing is complete, making those two where most of the magic happens. OnError may be less sexy, but it may be the most useful of the bunch, especially when dealing with external resources that may not always be available.

    A Quick Example

    I really struggled to think of a simple, "hello world" type application for this. In the presentation I saw, the sample application was a tool to query netflix's oData service. This was cool (especially the auto-complete) but seems like a bit much for a quick introduction, and I don't want to steal Jon's idea. Sometimes I wish I had one of those clocks that show several time zones at once, like the ones they use in call centers, so I could check before bothering some of my friends from lessthandot at unholy hours. I don't have nearly enough interest in figuring out every country's wacky daylight savings time rules to actually make such a thing, but decided it could be a decent example. It consists of several elements getting data from a single source, and doing some of their own processing on the data before passing it along, which is exactly what I wanted to show. So we'll work with the clockmaster 3000.

    We'll start with the observable. In this case it is just a class that sends time updates to any subscribers. I called it the Atomic Clock because it sounds cool. The Subscribe method is the most important here.

    1. class AtomicClock : IObservable<DateTime> {
    2.     IList<IObserver<DateTime>> observers = new List<IObserver<DateTime>>();
    3.     bool keepRunning;
    4.  
    5.     public IDisposable Subscribe(IObserver<DateTime> observer) {
    6.         observers.Add(observer);
    7.         return observer as IDisposable;
    8.     }
    9.  
    10.     public void Complete() {
    11.         keepRunning = false;
    12.         foreach (var observer in observers) {
    13.             observer.OnCompleted();
    14.         }
    15.     }
    16.  
    17.     public void Run() {
    18.         keepRunning = true;
    19.         while (observers.Count > 0 && keepRunning) {
    20.             SendTime();
    21.         }
    22.     }
    23.  
    24.     void SendTime() {
    25.         foreach (var observer in observers) {
    26.             observer.OnNext(DateTime.UtcNow);
    27.         }
    28.         System.Threading.Thread.Sleep(1000);
    29.     }
    30. }

    The most fun we're having here is probably SendTime method. It is not that interesting, but it's easy to see this being any kind of push-based notification. I really like the shift of control from the observer (where it would be using traditional event mechanisms) to the observed object that this represents. The observer is still in control of what to do with the information received, but the observed is in (more explicit) control of when it does it. If you're using .net 4 (I don't have it on my laptop) this could be sped up by using Parallel.ForEach (or use something like this on 3.5) but that's not too important at this point. Note that the Subscribe method returns an IDisposable - I'm not actually using it in this example but it would be very convenient when the observer needs to deal with unmanaged resources. The only other thing worth noting is the keepRunning boolean - this is used to signal to the clock that it can stop running it's running on a separate thread.

    Now to set up the observers. In this case, I'm just implementing the IObserver interface on a winforms control that contains a couple of labels (city name and time). They also take an offset property, which is used to localize the UTC time received from the atomic clock (as long as we are willing to pretend there is no such thing as daylight savings). There is some cruft in there to handle crossthread calls on controls, but it could be worse.

    1. public partial class Clock : UserControl, IObserver<DateTime> {
    2.     public Clock() {
    3.         InitializeComponent();
    4.     }
    5.  
    6.     public string City {
    7.         set { clockName.Text = value; }
    8.         get { return clockName.Text; }
    9.     }
    10.  
    11.     public double Offset { get; set; }
    12.  
    13.     public void OnCompleted() {
    14.         SetTimeText(time, "Not Responding");
    15.     }
    16.  
    17.     public void OnNext(DateTime next) {
    18.         string current = next.AddHours(Offset).ToLongTimeString();
    19.         SetTimeText(time, current);
    20.     }
    21.  
    22.     public void OnError(Exception ex) {
    23.         SetTimeText(time, "Error reaching time service");
    24.     }
    25.  
    26.     Action<Label, string> setterCallback = (toSet, text) => toSet.Text = text;
    27.  
    28.     void SetTimeText(Label toSet, string text) {
    29.         if (time.InvokeRequired) {
    30.             this.Invoke(setterCallback, toSet, text);
    31.         }
    32.         else {
    33.             setterCallback(toSet, text);
    34.         }
    35.     }
    36. }

    We can throw a few of these on a form, set up the correct city names and offsets, and then its time to wire everything up. The only buttons we've got are to start and stop the clock. Here's the code for the form:

    1. public partial class GlobalClock : Form {
    2.     AtomicClock atomicClock = new AtomicClock();
    3.     System.Threading.Thread backgroundThread;
    4.     bool running;
    5.  
    6.     public GlobalClock() {
    7.         InitializeComponent();
    8.         foreach (var control in this.Controls) {
    9.             if (control.GetType() == typeof(MasterClock.Clock)) {
    10.                 atomicClock.Subscribe(control as IObserver<DateTime>);
    11.             }
    12.         }
    13.         this.FormClosing += OnClosing;
    14.     }
    15.  
    16.     private void Run_Click(object sender, EventArgs e) {
    17.         if (!running) {
    18.             backgroundThread = new Thread(atomicClock.Run);
    19.             backgroundThread.Start();
    20.             running = true;
    21.         }
    22.     }
    23.  
    24.     private void Stop_Click(object sender, EventArgs e) {
    25.         StopService();
    26.     }
    27.  
    28.     void OnClosing(Object sender, FormClosingEventArgs e) {
    29.         StopService();
    30.     }
    31.  
    32.     void StopService() {
    33.         atomicClock.Complete();
    34.         running = false;
    35.     }
    36. }

    Hopefully this provided a decent introduction. A VS2008 solution containing all the code can be found over at github, and any further projects will be added there (this post focused on the ClockMaster3000 project).

    It appears that the reactive extensions can be tricked into working with mono (binaries can be found in an interesting location, C:\Program Files\Microsoft Cloud Programmability\Reactive Extensions if you need to copy them over). I had some trouble with this at first because of lingering GAC references in the project but it does appear that when referenced locally the reactive framework "just works". I'll update the project on github to include local references for any other mono folks.

    About the Author

    User bio imageAlex is a .net and SQL Server developer from southeastern PA, where he lives with a lovely wife and a veritable smorgasbord of pets. He recently completed a masters degree in Software Engineering from Penn State. He loves mountain biking, open source software, home brewing, Syracuse basketball, and the mono runtime.
    Social SitingsTwitterLinkedInHomePageLTD RSS Feed
    3378 views
    Instapaper

    2 comments

    Comment from: chaospandion [Member] Email
    chaospandion I was just working with WCF at work and I'm imaging a nice IObservable wrapper over a service. Maybe something like a job that processes a sequence of files and sends back a status to the client after each file.
    11/20/10 @ 18:34
    Comment from: Alex Ullrich [Member] Email
    Alex Ullrich That sounds pretty cool Matt. There'll be some stuff in the next post that might be helpful to you (for example, if you only wanted to react for files that processing failed for). I think the ultimate point to this series will be to use the reactive libraries to consume some kind of pushy service as well. After doing some UI work with them I am starting to come around on their capabilities for UI programming but I still think long running services are the killer use case.
    11/21/10 @ 10:12

    Leave a comment


    Your email address will not be revealed on this site.

    Your URL will be displayed.
    (Line breaks become <br />)
    (Name, email & website)
    (Allow users to contact you through a message form (your email will not be revealed.)