bling.github.io

This blog has relocated to bling.github.io.
Showing posts with label Coding. Show all posts
Showing posts with label Coding. Show all posts

Sunday, July 29, 2012

SnoopShell: Evolution

It’s been a while since I last announced SnoopShell, where I took some PowerShell and injected that into Snoop.  Well, I didn’t stop there!  I decided to continue working on it and adding more useful features.

Well, a bunch of things have changed.  For one, it’s no longer targeted at .NET 4 and PS v3 anymore (and you’ll soon know why).  Second, there’s a bunch of new features!

Automatic Profile Loading

Upon startup, the shell will look for a couple well known locations and automatically dot-source them to load them into the current session.  This works the same as the standard $profile.  The filename needs to be SnoopProfile.ps1, and the search paths are %USERPROFILE%, the WindowsPowerShell, and the Scripts folder deployed with Snoop.exe.

This is incredibly useful since you can write your own custom functions and scripts and have them available to you all the time.  As an added bonus, because of the dynamic nature of PowerShell, you can make modifications to the SnoopProfile.ps1, save, and then invoke a “. $profile” to reload the profile and update the session with your changes (all without restarting the application).

That’s awesome sauce indeed ;-)

PowerShell Provider

This was more of a for-fun thing at first just to see if I could do it.  Writing a PS provider is not fun at all, since it’s not very well documented and I actually needed some help from ILSpy to figure out how things really worked.  Nonetheless, it’s got some basic functionality that is helpful to navigate around.

image

Yep, the selected grid actually has a path, like how you would navigate the file system.  Let’s see what happens with a cd.

image

Cool, you can cd into the child “directory”, and it’ll automatically select the item in the tree view as well.  What if you’re lazy and don’t want to type?

image

Wildcards are supported.  And because the visual tree doesn’t exactly require unique names, I needed to trick it by adding a number after each duplicate item.  So the above matches the third Rectangle child of the Grid.

Code Injection

One of the cool things about Javascript is that it’s so darn easy to test.  You make a change, save, reload, and you’ll immediately see if something worked or not.  This feedback loop is so fast it changes how you work and formulate ideas.

In the static world, we don’t really have this luxury, and especially not when you’re working on a large project, which at work, takes just under a minute for a full rebuild.  And this is on a monster machine.  Because of this, we had to employ tricks and workarounds to speed things up, like messing with build configurations and build output paths to minimize duplicate work.  Despite that, it’s still a pain to wait for the application to start and all that jazz.

What if we could do the super fast feedback loop development, in a static world?  Well, now you can!

It starts with a simple function:

function replace-command([string]$msg = 'hello world') {
$action = { [system.windows.messagebox]::show($msg) }.GetNewClosure()
$cmd = new-object galasoft.mvvmlight.command.relaycommand([system.action]$action)
$selected.target.command = $cmd
}

The above function will replace anything that has a Command property on the target, like a Button or MenuItem, with a MessageBox showing a message.  For the curious, GetNewClosure is needed so that $msg is available within the inner script block.  Unlike C#, closures are not automatic.

Since PowerShell is dynamic, if you need to make a change, simply save the script, reload it with a dot-source, which will overwrite the existing function, and then set the target’s Command property again.  Awesome!

The only annoyance is converting PowerShell code back into C# code once you’re done.

Evolution

If you made it this far you didn’t forget about my comment about untargeting .NET 4 and PS v3.  Well, changes have been merged into the main branch!  Soon the masses will be able to experiment with supercharging their applications with PowerShell!

I’ll likely continue working on my fork as there’s still more goodies I’d like to add.  Stay tuned!

Sunday, July 1, 2012

SnoopShell: The marriage of Snoop WPF and PowerShell

I was given the opportunity to review a couple chapters of the excellent book PowerShell for Developers, written by my colleague Doug Finke.  One of the concepts in the book was embedding a PowerShell console into your application.  This idea is ingenious and we added this feature to our client’s software, and so far it has increased our productivity and opened the doors to many possibilities.

So what’s so cool about embedding a shell into your application?  Well, for starters, one of the immediate advantages is that it gives you the opportunity to test your application at run time.  If you are implementing the MVVM pattern then basically anything you can see in the UI is bound to some property in your view model.  What if you could expose an instance of your view model to the PowerShell console?  Yes, you would be able to interact with it directly, change values, and property change notification will kick in and update the UI.

The possibilities start to open up from there.  You can start scripting out common tasks – write once, run many times.  Or you can write a full fledge test suite as a script, give it to a QA tester, and have them run through it as a special kind of integration testing, one that happens with live, real data.  Or how about being able to modify code, at runtime, to try out an implementation without need to recompile or restart the application?  Sounds pretty awesome to me!

With this, I started thinking why don’t I try and add this to Snoop?  It’s a staple tool for any WPF developer, and adding scripting capabilities to Snoop will make it even more useful.

So, I sat down for a weekend and took a shot at it.  And with that, SnoopShell was born!

My fork of Snoop can be found here: https://github.com/bling/snoopwpf

It’s still in super-duper alpha, so features/ideas are still getting formulated, but here’s a glimpse of what it can do now.

The $root variable points to the root of the tree.  As you can see, Snoop represents this as a ApplicationTreeItem, which has a bunch of properties, the important ones being IsSelected and IsExpanded.

image

Let’s try interacting with the object by setting the IsExpanded to true.

image

So far so good.  Now let’s find my username using Ctrl+Shift.  The $selected variable is automatically synchronized with the selected item in the tree.

image

Let’s do some black magic and change my name.

image

Finally, let’s find every ListBox in the application.  Find-Item is used to recursively find everything in the visual tree which is a ListBox.

image

And from here, it’s as simple as grabbing the DataContext of any control to get access to the view model.

By the way, this is targeting PowerShell V3, so you will need to have the RC installed.

Try it out and let me know what you think!

Sunday, June 3, 2012

N2N: .NET 2 Node

Well, it’s been quite a while since I’ve blogged about…well…anything, and I figured it’s about time I get off my lazy butt and do something with my spare time on weekends.  What better option than to see what all the hype is about Node?  I had to do it sooner or later.

As any newbie would do, they go to Google and type “nodejs tutorial”.  The Node Beginner Book came up first, so I went with that.  It was an excellent tutorial.  Prior to this I also skimmed through the book JavaScript, The Good Parts, so I had a basic understanding of the language syntax.

One of the first oddities I noticed, was that NodeJS seems to have a convention of comma-first.  You notice this immediately because most examples start with require(‘module’), and if they require more than one module, the second line is prefixed with a comma (as opposed to the more traditional comma at the end of the line).  I apparently missed the discussion by 2 years!  It was still interesting nonetheless.

As someone with a strong .NET background, I definitely experienced all the usual ‘gotchas’:

  • == vs ===
  • falsey values
  • variable hoisting

Once you understand all of these things, Javascript isn’t so bad.  Oh, and of course understanding closures will get you a long way in being effective with Javascript, because that’s what you need to use to do proper scoping.  If C# didn’t have lambdas and closures it would have been a much longer journey to “get it”.

Not too longer after, I deployed my first Heroku app running on NodeJS.

Anyways, enough with the prologue…I won’t bore you with anymore beginner/tutorial stuff.

Let’s get on with what I plan on doing over a multi-part blog series.  When I build something on my own time, I can’t build something just for the hell of it to learn something….that’s not enough.  If I build something it has to be useful – something that I (or someone else) will find valuable.

I won’t reveal what it is yet, but it’s going to involve Node/MongoDB on the backend, with Backbone on the front-end.  Should be fun :-)

Monday, October 31, 2011

My Thoughts on MEF

Ever since MEF was conceived, despite the authors saying that it is not an IoC container, it has since evolved to become one of the more popular IoC containers.  I’ve always avoided it because I disagree with using attributes, and I’ve had no reason to use it over Autofac or Windsor.

Recently, I found a reason to use it – Metro-style applications only support MEF so far.  My Twitter client ping.pong uses Autofac as the IoC container.  It uses some very basic functionality like factories and hooks.  To my surprise, MEF has no support for either of these.

Coming across these limitations solidifies my opinion that MEF is a plugin container, not an IoC container.

First let’s take a look at automated factories. What I mean is that by registering Foo, like so:

container.RegisterType<Foo>();

the container will automatically provide us a Func<Foo> without explicitly having to register it. This can be useful when you want to create an instance of Foo some time in the future rather than at constructor time.  You can do this with MEF via an ExportFactory<T>, but it’s limited because you cannot override dependencies at resolve time.

For example, let’s say Foo has a constructor of Foo(Bar1, Bar2, Bar3). With MEF, you have no control at resolution time what the Bars are. A container that has support for automated factories (like Autofac and Castle Windsor), will let you resolve a Func<Bar1, Foo>, which lets you override Bar1 at resolve time. Similarly, you can resolve a Func<Bar1, Bar2, Bar3, Foo> and override all dependencies. Any dependencies not overridden fall back to their configuration in the bootstrapper. This is a very useful feature, and coupled with the scoping features for automatic disposal it opens up many doors for elegant solutions for what otherwise are complicated problems.

On to the second point; MEF has limited extension points. This one sounds odd since MEF is all about designing decoupled plugins so surely it should have extension points! The problem here is that MEF is designed as an explicit API (attributes are required) rather than an implicit API. In Autofac, you can scan an assembly and register every type. In MEF, every class needs to have an [Export] on it.  It also baffles my mind why [ImportingConstructor] is required even when there’s only one constructor. All this explicitness means you lose a bunch of “free” extension points that typical IoC containers have, like this:

b.RegisterAssemblyTypes(GetType().Assembly)
  .OnActivated(x => x.Context.Resolve<IEventAggregator>().Subscribe(x.Instance));

What the code above is saying that every time any component is activated, it will subscribe to the event aggregator. If the component doesn’t IHandle<> any messages, it’s a no-op and continues on. If the instance does IHandle<> messages, this will ensure it’s hooked up.

The closest thing I could find in MEF was IPartImportsSatisfiedNotification (yes, an interface, more explicitness!).  It contains a single method OnImportsSatisfied() which gets called when the part is created.  Needless to say, the one line of code from Autofac would translate into a method for every implementation of IHandle<>, and since OnImportsSatisfied() contains no contextual information, every component will need IEventAggregator injected just to be able to call Subscribe.

To fully complete this example, Autofac has the following methods when registering a component: OnRegistered, OnPreparing, OnActivating, OnActivated, and OnRelease.  Each of these methods gives you complete contextual information at the time it is called like access to the current scope of the container, the instance (if applicable), which component which requested the dependency, etc.  This makes it almost too easy to extend the container.

For MEF, the only real extension point is an ExportProvider.  It is pretty low level (all it does is parse attributes for you) so to write anything similar for MEF requires a lot more code.  To further illustrate this point, compare the interception modules from AutofacContrib and MefContrib.  The Autofac implementation is a single file with a couple extension methods.  The MEF implementation is an entire namespace, over multiple classes, not the mention that it also relies on other infrastructure code in MefContrib.  Basically, the guys that wrote MefContrib had to write a mini-container within MEF.

MEF is great for building extremely loosely coupled applications.  I don’t think it has any business in an application where you know and own all of the dependencies; there are simply better libraries for that.

Wednesday, September 21, 2011

Building a Real-time Push App with Silverlight: Part 8

 

Exploring Caliburn Micro

As I hinted in earlier posts, Caliburn Micro has some wicked conventions that makes for writing MVVM super easy, and it also have a very convenient syntax for hooking up events.  For example, the following:

<Button Content="R">
   <i:Interaction.Triggers>
       <i:EventTrigger EventName="Click">
           <i:InvokeCommandAction Command="{Binding ReplyCommand}" CommandParameter="{Binding}" />
       </i:EventTrigger>
   </i:Interaction.Triggers>
</Button>

Can be rewritten like this:

<Button Content="R" cal:Message.Attach="[Reply($dataContext)]" />

There are some smarts going on here.  Caliburn Micro will default to the Click event for buttons.  For a full syntax, it would be cal:Message.Attach=”[Event Click] = [Reply($dataContext)]”.  As you can imagine, that will call the Reply method and pass in the current data context.  You can also pass in other things like $this, $source, or $executionContext for full access to anything and everything Caliburn Micro itself has access to.

The coolest thing about this is it gives you some wicked control over how your data context gets set.  Ever struggled with popup windows or data grids and using weird hacks to get the binding correct?  Caliburn Micro makes this very easy.  Here’s an example.

  1. I have a DataTemplate which renders the UI for the model Tweet.
  2. Tweet is just a simple class which holds only properties.
  3. Inside the DataTemplate, I have some buttons that when the user clicks will reply, retweet, quote, or direct message.

The Tweet class is purely for modeling data, so adding any methods would be bad practice.  Also, since I’m in a DataTemplate I can’t easily reference another control with ElementName (in this case I need the containing parent’s DataContext).  And to add insult to injury, Silverlight 4 doesn’t have RelativeSource ancestor type.  So how do I solve this?

<StackPanel VerticalAlignment="Bottom" cal:Action.TargetWithoutContext="shell" Orientation="Horizontal">
    <Button Content="R" cal:Message.Attach="[Reply($dataContext)]" />
    <Button Content="RT" cal:Message.Attach="[Retweet($dataContext)]" />
    <Button Content="Q" cal:Message.Attach="[Quote($dataContext)]" />
    <Button Content="DM" cal:Message.Attach="[DirectMessage($dataContext)]" />
</StackPanel>

The secret is the attached property TargetWithoutContext.  As the name implies, it will set the target for all the ActionMessages attached to all the buttons, without setting the context.  If I used the Target attached property, it would set all of the Buttons’ data context to the same object – not what we want.  Since the Button’s data context remains intact, we can call “Reply($dataContext)”, which calls the Reply method on the target object (set on the StackPanel) and pass in the Tweet.  “shell” is the key of the service that I registered into the container.

Originally I wanted this entire series to be able writing a fast push data app with Silverlight and Rx, and now I’m finding that I’m writing an entire Twitter client because it’s so much fun :-).

I’m going to make another release soon.  While the first release was merely experimental, the next one will be useful enough to potentially use full time.  As you can probably tell with this blog post, it supports all the actions mentioned previously (and it’ll appear on mouse hover):

image

The tweet box is much improved and shows you how many character you have left:

image

And it’s smart enough to auto wrap http links via Twitter’s t.co service, and the counter takes that into account.  Some interesting things to note is that in the future all links will be wrapped t.co.  Looks like Twitter is trying to eat up bt.ly or something.

Clicking on @users and #topics will automatically open a new timeline and subscribe to those tweets.  It is almost full featured enough to become my main Twitter client.  There are certain features still missing, and it’s purely based on when I have time to port them over.

As always, you can install directly from here, or you can grab the code on the GitHub page!

Next post will be about Rx from a very top level perspective and how it influenced my code from beginning to be experienced and all refactorings in between.  Stay tuned!

Friday, September 16, 2011

Building a Real-time Push App with Silverlight: Part 7

Infrastructure Refactor

A lot of things changed internally, and I mean….a lot….

From an infrastructure standpoint, I decided to remove the dependency on LinqToTwitter, and I replaced it with Hammock.  A couple things led me to this decision, one being the Silverlight support wasn’t as good as I’d hoped, and the streaming API implementation was limited.  After reading the Twitter documentation I realized that the REST API was super simple and I’d be better off writing a simple interface to it.

I heard good things about Hammock, so I decided to give that one a try (I wasn’t going to go as far as reimplementing OAuth).  It was pretty easy to set up and in the end I was able to get Twitter working again and with less lines of code compared to the beginning of the refactor.

Goals

I had a couple goals for this project:

  • Learn:  I was a complete newbie to Reactive Extensions when I started but now I understand it enough to hit the ground running with it.  I’m still learning about more conventions available to Caliburn.Micro.
  • UX:  I wanted to learn a little more about interface design.  I wanted to know how little changes to gradients, shadows, colors, etc. could have a radically effect in the end result.
  • Performance:  It should be fast.  It should be able to react to real-time data.  And it should do it with low CPU utilization.
  • Concise:  I am a huge advocate for KISS.  I like convention over configuration.  I like implementing something in 2 lines of code rather than 20 (assuming it’s not cryptic).  As I was writing the app and refactoring, if there was an opportunity to remove a line of code, I did it.  The result is that the app currently consists of less than 500 lines of code as of this post (excluding XAML).

Tidbits

What are some interest things I learned?

  • System.Json is an amazing assembly.  All you need to do is invoke JsonValue.Parse on a string and it will create a JsonValue for you, which will be a dictionary of key/value pairs.  What’s more, by doing something like “string s = json[“text”]” will do an explicit conversion and unescape JSON characters, and only via the explicit operator.  Calling ToString(), even though converting it to a string, will not unescape.  This was completely undocumented and only found when I looked at the source code via Resharper’s external sources feature.
  • Rx is awesome.  When I ran into performance problems of trying to stream tweets from the world that contained the letter ‘a’ all I had to do was add an operator to improve the performance (in this case it was Buffer).  It should be noted that it is very important to understand what Rx is doing underneath the hood to realize its benefits.  Rx lets you refactor 30 lines of async code into 1 operator, but it’s still doing that 30 lines of code – you just don’t see it.
  • I really, really, like the conventions available from Caliburn.  Some of the features that come out of the box from this very small library saves me from writing a lot of boilerplate code like commands, triggers, and evening bindings (Caliburn will auto bind x:Name to a property).
  • Twitter’s documentation for user streams currently sucks and some trial and error was required to get it working.

What is the end result of all this effort?  We have a styled Twitter app that can update your status, pull your home/mentions timeline, and most importantly will stream all subsequent tweets.  There’s no pulling and no limits.  You will get a tweet of everyone you follow in real-time as it happens.

Moreover, there’s a feature to connect to the Streaming API to search Twitter for anything.  To get an idea of what we’re talking about, here’s a full screenshot of it:

image

You read that right.  I’m streaming any tweet in the world that has the words ‘and’, ‘the’, ‘yes’, or ‘no’ in them.  This is streaming around 400kB/s continuously and CPU utilization is under 25%.  The tweets are coming so fast it’s impossible to read them (at a rate of 50 tweets/second), so ideally you’d want to specify realistic search terms.

Moreover, the majority of the performance cost is actually downloading all the profile images.  If I take took out pictures I could stream any tweet in the world that has the letter ‘e’ in it at under 10% CPU.  It looks like Twitter limits the rate of tweets to 50 tweets/second because that was the rate for this one as well.

Features are minimalistic.  You can update your status, but you can’t DM, you can’t RT, you can’t do any of the normal things.  My original goal was not to write another Twitter client, but it’s actually quite fun to do so, so I’ll probably eventually get all features in.

And as promised, it’s up on GitHub, and version 0.0.0.1 alpha (yes! expect bugs!!) is available in the downloads section.  Or, here’s a direct link to the XAP file on my Dropbox.  Have fun!

Thursday, September 8, 2011

Building a Real-time Push App with Silverlight: Part 5

I planned on this post to be about UI, but I’m going to defer that until the next post.  I said from the start of this series that I would document about everything about building the application from scratch, including my struggles.

And with that I want to mention something that got me scratching my head one too many times.  It was with how I used LinqToTwitter.  Here is the source code which you can immediately copy/paste into a blank project to reproduce:

   1: public partial class MainPage : UserControl
   2: {
   3:    private readonly TwitterContext _context = new TwitterContext();
   4:    private readonly ViewModel _vm1, _vm2, _vm3;
   5:  
   6:    public MainPage()
   7:    {
   8:        InitializeComponent();
   9:        _vm1 = new ViewModel(_context);
  10:        _vm2 = new ViewModel(_context);
  11:        _vm3 = new ViewModel(_context);
  12:        _vm1.Callback += () => Debug.WriteLine("Callback of VM1: " + _vm1.LocalState);
  13:        _vm2.Callback += () => Debug.WriteLine("Callback of VM2: " + _vm2.LocalState);
  14:        _vm3.Callback += () => Debug.WriteLine("Callback of VM3: " + _vm3.LocalState);
  15:  
  16:        _vm1.Start();
  17:        _vm2.Start();
  18:        _vm3.Start();
  19:    }
  20: }
  21:  
  22: public class ViewModel
  23: {
  24:    private readonly TwitterContext _context;
  25:    public event Action Callback;
  26:  
  27:    public int LocalState;
  28:  
  29:    public ViewModel(TwitterContext context)
  30:    {
  31:        _context = context;
  32:    }
  33:  
  34:    public void Start()
  35:    {
  36:        var query = (from s in _context.Status
  37:                     where s.Type == StatusType.Public && s.Count == 10
  38:                     select s);
  39:        Debug.WriteLine("Hash code of ViewModel: " + query.GetHashCode());
  40:        query.AsyncCallback(statuses =>
  41:        {
  42:            LocalState++;
  43:            Debug.WriteLine("Hash code inside callback: " + GetHashCode());
  44:            Callback();
  45:        }).FirstOrDefault();
  46:    }
  47: }

Now, if you run this, you will see that only one of the view models will get its state updated.  Huh?!

How is that possible?  I started getting paranoid so I even added the local state variable “just in case.”

Well, I had to look into the source code of LinqToTwitter to figure out exactly what happened.  Here is the code for AsyncCallback:

public static IQueryable<T> AsyncCallback<T>(this IQueryable<T> queryType, Action<IEnumerable<T>> callback)
 {
     (queryType.Provider as TwitterQueryProvider)
         .Context
         .TwitterExecutor
         .AsyncCallback = callback;
 
     return queryType;
 }

See what happened?  The callback gets overwritten every time you call this method.  Even though the call to FirstOrDefault() causes all 3 expressions to evaluate, only the last view model will get values because that’s the with the callback attached.

Lesson of the day: The AsyncCallback extension method for LinqToTwitter is not thread-safe.

So…the question is, how do we make it thread safe?  I just replaced wrapped the AsyncCallback with another extension method:

private static readonly AutoResetEvent _twitterEvt = new AutoResetEvent(true);
 
public static void AsyncTwitterCallback<T>(this IQueryable<T> twitter, Action<IEnumerable<T>> callback)
{
    Observable.Start(() =>
    {
        _twitterEvt.WaitOne();
 
        twitter.AsyncCallback(results =>
        {
            try
            {
                callback(results);
            }
            finally
            {
                _twitterEvt.Set();
            }
        }).FirstOrDefault();
    });
}
Nothing complicated – just a simple wait handle to ensure only 1 thread can go through at a time.

Hopefully upstream fixes this, or at least documents it.

Monday, September 5, 2011

Building a Real-time Push App with Silverlight: Part 4

Originally I wanted to avoid bringing in external libraries to keep the app as lean as possible, but then I realized that I would spend too much time reinventing the wheel.  Twitter is deprecating basic authentication in the near future, which makes OAuth no longer optional.  Rather than writing yet another Twitter client (if you’re curious I found a great reference here), I fired up NuGet and brought in LinqToTwitter, and while I’m there I brought in Autofac and Caliburn.Micro as well.

Naturally, LinqToTwitter will work nicely with Rx because as name implies it uses LINQ heavily.  Caliburn.Micro is a MVVM library which I’ve always wanted an excuse to try because of features like this:

<ListBox cal:Message.Attach="[Event Loaded] = [LoadList($dataContext)]" />

That’s only scratching the surface of what Caliburn can do, so it will be a fresh breath of air to see what else it can do.

By default, Caliburn uses MEF to wire up its bootstrapper.  After adding a couple [Import]s and [Export]s, I knew it wasn’t for me.  It works well for writing plugins, i.e. external dependencies because of its built-in assembly scanning capabilities, but for injecting internal dependencies, other IoC containers do a much better job of that.  I used Castle Windsor in past projects, but for a change I’m going to use Autofac which I haven’t used since v2 came out.

When this was all said and done the View was the only thing that didn’t change.  Everything underneath either changed radically or was deleted altogether (because LinqToTwitter provided it).  I added OAuth support and registered my application with Twitter, and with that was the birth of Ping Pong.

This took much longer than expected.  Silverlight 5 RC just came out and it broke pretty much any container (including MEF) for OOB because of a TypeLoadException.  I haven’t been using too many v5 features, so for the time being I downgraded to v4 to get the project working until RC2 comes out.

Integrating LinqToTwitter was a challenge.  The project site has a lot of good documentation, but most of it was for desktop, not Silverlight, and because of that I banged my head a couple times.  I wish I grabbed the source code earlier because it’s there where you’ll find hundreds of working examples (in code!) to do everything with the library (and in Silverlight).

After all that, PingPong now has 3 columns (home, public, sampling) that dynamically resizes (it’s surprising that MetroTwit is the only client that does this….) to the window size.

image

Oh, and there’s pictures now!  The streaming time line takes significantly more CPU now that it has to load images, but we’re still sitting at around 5-10% for what is continuously streaming data and loading pictures.  Not too shabby!  (It took a couple tries to get a PG-13 screenshot from the public/streaming time lines…)

To conclude this post in the series, I’m going to talk about converting an asynchronous operation into an Observable that does not follow any predefined pattern.

Creating an Observable

One of Silverlight’s limitations is that almost everything needs to be an asynchronous call.  In regards to LinqToTwitter, something like this will fail (but work on desktop):

var tweets = (from t in context.Status
              where t.Type == StatusType.Public
              select t).ToArray();

On Silverlight you will get a single empty element.  To get it working, there is an extension method that comes with the library, and you use it like this:

(from t in context.Status
 where t.Type == StatusType.Public
 select t)
  .AsyncCallback(tweets => { /* do something with it */ })
  .FirstOrDefault();

Code is self-explanatory.  The FirstOrDefault() exists only to initiate the expression, otherwise it wouldn’t do anything.  So now the question is how do we convert that into an Rx Observable?

Every time I write an Rx query I try to use the least amount of state as possible.  This helps to keep the number unexpected anomalies to a minimum.  In the following section of code, I was able to get it down to 2 fields: _sinceId, and Context.  There is probably some operator that will let me save the sinceId variable from one observable to the next but I wasn’t able to figure it out.  In any case, I came up with this:

_subscription =
    Observable.Create<Tweet>(
        ob => Observable.Interval(TimeSpan.FromSeconds(60))
                  .StartWith(-1)
                  .SubscribeOnThreadPool()
                  .Subscribe(_ =>
                  {
                      ulong sinceId;
                      (ulong.TryParse(_sinceId, out sinceId)
                           ? Context.Status.Where(s => s.Type == statusType && s.Count == 200)
                           : Context.Status.Where(s => s.Type == statusType && s.Count == 200 && s.SinceID == sinceId))
                          .AsyncCallback(statuses =>
                          {
                              foreach (var status in statuses)
                              {
                                  ob.OnNext(new Tweet(status));
                                  _sinceId = status.StatusID;
                              }
                          })
                          .FirstOrDefault(); // materalize the results
                  }))
        .DispatcherSubscribe(SubscribeToTweet);

That contains some custom code:

  • Context:  is a TwitterContext from LinqToTwitter
  • DispatcherSubscribe:  is a helper extension method which Subscribes on the ThreadPool, Observes on the Dispatcher, and then Subscribes with the specified action
  • SubscribeToTweet: a method in the base class which adds to a ObservableCollection so the UI gets updated

To translate the code, here is a basic flow of what’s happening:

  1. Observable.Create wraps the subscription of another Observable.  It provides access to an IObserver ob which lets you explicitly invoke OnNext().
  2. Observable.Interval will raise an observable every 60 seconds.
  3. The subscription of Observable.Interval will query the TwitterContext for the next set of tweets.
  4. Inside the AsyncCallback, it invokes ob.OnNext as well as keeps track of the ID so the next time it queries it only gets newer tweets.
  5. Finally, DispatcherSubscribe will take the Tweet object and add it to an ObservableCollection<Tweet>, which notifies the UI.

As always, you should “clean up your garbage”.  In this respect I was pretty impressed with Rx as it was able to clean up the entire chain of observables with a single call to _subscription.Dispose().  Nice!

In the next post I’m going to switch back to UI and completely restyle the application.  The code will hit GitHub soon as well (I promise!).  Stay tuned…