Thursday Night

Paul Betts’s personal website / blog / what-have-you

Threading bugs in ReactiveUI in Silverlight

The symptoms of this bug

If you use the Silverlight version of ReactiveUI, you will currently encounter a lot of issues that appear to be the classic InvalidOperationException, where a Silverlight object is being accessed by a background thread – it might look something like this:


at System.Windows.Threading.Dispatcher.VerifyAccess()
at System.Windows.DependencyObject.GetValue(DependencyProperty dp)
at System.Windows.Controls.Primitives.ButtonBase.get_Command()
at System.Windows.Controls.Primitives.ButtonBase.UpdateCanExecute()
at
System.Windows.Controls.Primitives.ButtonBase.OnCanExecuteChanged(Object
sender, EventArgs e)
at ReactiveUI.Xaml.ReactiveCommand.b__0(Boolean b)
at
ReactiveUI.ObservableAsPropertyHelper`1.<>c__DisplayClass4.< .ctor>b__0(T
x)
at System.Reactive.AnonymousObserver`1.Next(T value)
at System.Reactive.AbstractObserver`1.OnNext(T value)
at System.Reactive.AnonymousObservable`1.AutoDetachObserver.Next(T
value)
at System.Reactive.AbstractObserver`1.OnNext(T value)
at
System.Reactive.ScheduledObserver`1.<>c__DisplayClass639.b__637()
at System.Reactive.ScheduledObserver`1.b__634(Action
self)

You’ll also see the message in the Console output, "WPF Rx.NET DLL reference not added - using Event Loop"

How to fix it

The easiest way to fix this is by adding this block to your App.xaml.cs:

protected override void OnStartup(StartupEventArgs e)
{
    RxApp.DeferredScheduler = DispatcherScheduler.Instance;
    base.OnStartup(e);
}

What’s the Deal??

One of the goals of RxUI was that the core library didn’t have a dependency on WPF/Silverlight: since an Observable Model object or an Observable collection is useful regardless of the domain! However, to do this, we need to do some trickery to ensure the experience is correct.

In a Console app, we don’t have a message loop, so we use EventLoopScheduler; this has the result of creating a single thread where all of our “UI actions” happen – it’s a Dispatcher without the Dispatcher. In WPF/Silverlight, we do have a real message loop, so we want to use DispatcherScheduler as our “put it on the UI thread” scheduler – but, we can’t link to System.Reactive.Threading.dll without pulling in WPF, even if we don’t use it!

What I do is, in the RxApp startup routine, I use Reflection to attempt to find the DispatcherScheduler Type and instantiate it at runtime. In WPF, the code that is currently there works like gangbusters – in Silverlight though, you have to be way more specificLukas Cenovsky does a great job tracking down the bug in this mail thread: you have to specify not just the fully namespaced Type name, but the fully qualified assembly name! (i.e. not just “System.Reactive.Windows.Threading”, but all of the version details and the public key token.

How come this doesn’t happen in unit tests?

Because in Unit Tests, there is no working Dispatcher (you can queue items to it, but they will never run) – ReactiveUI knows this and switches the Scheduler automatically in a unit test runner to Immediate, which makes writing simple unit tests far easier. That has the side-effect for me though, that some of my code is never covered by a unit test. Oops!

tl;dr; - Reflection works a lot differently on Silverlight, and is generally way more of a pain.

Written by Paul Betts

June 23rd, 2011 at 3:41 pm