Поделиться через


Reactive Extensions v2.0 has arrived!

Today, we’re extremely pleased to announce the availability of Reactive Extensions for .NET (Rx) v2.0 RTM, aligned with the availability of Visual Studio 2012 RTM and Windows 8 RTM for MSDN subscribers. This is a major milestone for the Rx project and we hope you’ll love what you see!

In this post, we’ll focus on how to download and install the bits for use in various application frameworks. Unlike previous posts about the v2.0 pre-releases, we’ll defer further technical details to a series of follow-up posts. Nonetheless, we’ll give a brief introduction into the use of Portable Library with Rx v2.0 RTM.

Note:   We’ve written this post in the typical font used for big announcements nowadays – Comic Sans – in honor of the Higgs boson discovery. In case you don’t want to partake in this celebration for the remainder of the post, click here to switch fonts.

Before we get started, make a note of the supported platforms for this release:

  • .NET Framework 4
  • .NET Framework 4.5
  • .NET Framework 4.5 for Windows Store apps
  • Silverlight 5
  • Windows Phone 7.5

Although this post was authored on Windows 8 using Visual Studio 2012 for screenshots, Rx can be used with Visual Studio 2010, and/or on older versions of the operating system as well. (For example, at the time of writing this post, Windows Phone development wasn’t yet publicly available in Visual Studio 2012, so that’d be a case where you have to use Visual Studio 2010 for the time being.)

Reactive Extensions for JavaScript (RxJS) users can expect the v2.0 release – including support for WinJS used in Windows Store apps – to hit the web very soon. Watch this blog for the announcement.

Option 1 – Installing the Rx SDK using Windows Installer

The traditional way of installing the Reactive Extensions SDK is through the Windows Installer (MSI) package one can get from the Download Center. Using this approach, you’ll get tight integration with Visual Studio through the Add Reference dialog for various target platforms.

image

We’ll talk about the integration with Visual Studio shortly. Let’s focus on the target platforms first. After clicking through the EULA page, you’re presented with an option to install the “Typical” feature set of the SDK, the “Complete” on, or to customize the installation using “Custom”. Let’s choose the latter option to illustrate the target platforms and talk a bit about some important changes here.

image

As you can see from the next screenshot, the structure of the SDK has changed quite a bit:

image

First of all, notice how the “.NET Framework 4” binaries are not installed by default. We chose this approach to reduce the clutter in the Add Reference dialog in Visual Studio 2012 when installing both the “.NET Framework 4.5” and “.NET Framework 4” assemblies.

When both sets of assemblies are installed on the system, projects targeting .NET Framework 4.5 will have duplicate entries for the Rx assemblies in the Add Reference dialog. Because .NET 4.5 is fully compatible with .NET 4 assemblies, the project management system shows the .NET 4 SDK assemblies as well, alongside the .NET 4.5 SDK assemblies which are optimized for the target platform.

Though one can safely run Rx v2.0 on .NET 4.5 using our .NET 4 assemblies, this is suboptimal. Various features such as “await” support on observable sequences and improved exception propagation (using ExceptionDispatchInfo) wouldn’t be available. Also, users have to make sure not to mix-and-match Rx assemblies targeting different versions of the .NET Framework. For example, using System.Reactive.Core built for .NET 4 together with a copy of System.Reactive.Linq built for .NET 4.5 may or may not work. Such combinations were never tested and will likely result in unexpected runtime behavior.

Tip: If you’re planning on using Rx v2.0 for both .NET Framework 4 and .NET Framework 4.5 projects, consider using NuGet to prevent issues when referencing assemblies. Using NuGet – which we’ll cover further on – it suffices to pick the Rx packages you need, and the package manager will take care of downloading the binaries that match (or are best suited for) your project’s target platform.

Secondly, the refactoring of Rx v2.0 into a Portable Library based core and platform-specific assemblies for “.NET Framework 4.5” and “.NET for Windows Store apps” (used by Windows 8 XAML applications) is reflected in the feature tree as well. We’ll come back to this in a bit.

After completing the installation, you’ll find the product binaries for selected target platforms under “Program Files (x86)\Microsoft SDKs\Reactive Extensions\v2.0” (omit the x86 part in the path if you’re on a 32-bit system). We changed the installation location – compared to our v1.x release – to consolidate all of Microsoft’s SDKs under the same file system location.

image

At this point, you’re ready to start playing with Rx v2.0 inside Visual Studio 2012. In the screenshot below, you can see the Rx assemblies show up in the Add Reference dialog for a Console Application project targeting .NET Framework 4.5:

image

If you decide to use the Reference Manager instead of NuGet (see further), make sure to include System.Reactive.PlatformServices. This assembly contains the so-called platform enlightenment provider that’s responsible to discover platform-specific capabilities for use by the platform-neutral core assemblies that are based on Portable Library. In the selection above, System.Reactive.Interfaces, System.Reactive.Core, and System.Reactive.Linq are all portable assemblies that are shared with Rx v2.0 for .NET 4.5 for Windows Store apps. We’ll come back to enlightenments later in this post.

One additional thing that the MSI-based installer takes care of is installing the so-called Rx v2.0 “Extension SDK” for Windows Store apps. In such projects, the Add Reference dialog has Rx presence in two spots. First of all, the regular Assemblies, Extensions tab contains all of the Rx assemblies in one spot:

image

When going down this route, make sure to include System.Reactive.PlatformServices for the same reasons as the ones we discussed before. Doing so will enable Rx to take advantage of the WinRT APIs to introduce concurrency on the WinRT thread pool. However, when using the Extension SDK model, you don’t have to worry about picking the right set of assemblies at all. On the Windows, Extensions tab in the Reference Manager dialog you’ll find a one-click way to include all of Rx, tailored for Windows Store apps:

image

This new Extension SDK model greatly simplifies the procedure of using another SDK, regardless of its internal organization. In the past, different pieces of functionality were often fused together in massive assemblies without proper layering, merely to simplify development and deployment operations. In fact, for Rx v1.0 ease of adoption was an important goal. Long time Rx fans may recall an old split of the Rx API – prior to the v1.0 RTM release – where we had an assembly called System.CoreEx. In order to simplify the usage of Rx, we decided to fuse this assembly with System.Reactive.

However, as portability became an important goal, some things had to be split into a separate assembly (System.Reactive.PlatformServices). At the same time, some use cases didn’t require the full set of Rx operators to be deployed, e.g. because some apps’ sole purpose is to render a sequence on a UI thread. As a result, the core of Rx was split into System.Reactive.Core and System.Reactive.Linq. The former contains core scheduler infrastructure as well as a bunch of base classes, while the latter contains the LINQ query language layer of Rx. Assemblies like System.Reactive.Windows.Threading (for synchronization with the UI in Silverlight, WPF, Windows Phone, or Windows Store apps) only depend on System.Reactive.Core.

Thanks to the new Extension SDK model, as well as the increasing popularity of the NuGet package manager, the inclusion of Rx (or any other SDK for that matter) has become largely friction-free, whilst allowing a better internal organization of the API with proper layering in place. From a deployment point of view, an increasing amount of application models rely on packaging mechanisms, e.g. to upload apps to a store or to a cloud platform, taking away the friction of copying many assemblies.

After installing the Rx SDK, you’ll find the Extension SDK showing up in the Tools, Extensions and Updates dialog as well:

image

Intermezzo – The refactored API surface

From the discussion above, you’ll likely have noticed the refactored API surface with different assembly names than what you were used to in Rx v1.0. As explained briefly, part of this has to do with splitting platform-specific from platform-neutral functionality, which allowed us to support Portable Library for projects that use Rx. The layered cake diagram of Rx, when hosted in a .NET 4.5 “desktop app” process is shown below:

image

In here, the green assemblies are portable, meaning they don’t rely on specifics of the underlying platform and can be ported to other target platforms as well. In particular, those assemblies are shared with the Rx v2.0 SDK features targeting .NET 4.5 for Windows Store apps. As a result, this common core cannot depend on various capabilities that don’t exist in the intersection of those platforms, such as thread creation, timer, or thread pool APIs.

For Rx to achieve optimal performance, it needs to find out about platform-specific capabilities that can be used to enhance performance and provide the best possible experience. This is where the blue assembly on the right comes in. While it’s a separate assembly, various infrastructure-only (i.e. not for public consumption) interfaces provide a very tight integration with the portable subset of Rx. When this so-called “platform enlightenment provider” is not available, the portable core falls back to functionality in the intersection of the targeted portable platforms.

The orange assemblies contain bridges to platform-specific APIs such as Windows Forms and WPF (for synchronization with the UI thread), which existed before in Rx v1.0. One notable new assembly is System.Reactive.Runtime.Remoting which contains the .NET Remoting support allowing observable sequences to be exposed as a MarshalByRefObject.

When targeting .NET 4.5 for Windows Store apps, there are different platform-specific assemblies, including the blue enlightenment provider that now leverages Windows Runtime functionality, as well as the orange assemblies that provide access to platform-specific APIs such as Windows XAML and various Windows Runtime APIs (such as the new IAsyncOperation<T> interface). On this platform, the picture looks as follows:

image

The green assemblies are byte-by-byte identical to the ones used for Rx v2.0 targeting .NET 4.5 “desktop apps”, and are really Portable Library assemblies. When building a Portable Class Library (discussed in a future blog post dedicated to this topic), you’ll directly include those assemblies as well.

In order to show you the effect of running the same portable core of Rx with different System.Reactive.PlatformServices assemblies, have a look at the two call stacks illustrated below. The first runs a timer-based Rx source generator in a .NET 4.5 Console Application, while the latter runs exactly the same code in a Windows Store app.

image

versus

image

As you can see, running the same piece of portable code on different platforms resulted in Rx taking advantage of whatever is the best possible way to run timers for the target platform. Notice the System.Reactive.PlatformServices assembly show up in both runs; this is where the platform-specific Rx functionality sneaked itself in underneath the portable System.Reactive.Core and System.Reactive.Linq assemblies.

 

Option 2 – Installing the Rx assemblies using NuGet

An alternative way of including Rx into your projects is by using NuGet. Starting with Visual Studio 2012, you’ll find the Package Manager directly integrated in the IDE experience, so you won’t have to do anything special to use NuGet. For previous releases of Visual Studio, follow the instructions on www.nuget.org to download and install the Package Manager.

The following package names are commonly used with Reactive Extensions v2.0:

  • Rx-Main – installs the System.Reactive.Interfaces, System.Reactive.Core, and System.Reactive.Linq assemblies, as well as the project’s target platform enlightenment provider in System.Reactive.PlatformServices.
  • Rx-Xaml – installs Rx-Main as well as System.Reactive.Windows.Threading. This package is used for UI synchronization and can be used on any platform that supports XAML, including WPF, Silverlight, Windows Phone, and Windows Store apps.
  • Rx-WinForms – installs Rx-Main as well as System.Reactive.Windows.Forms. Similar to the XAML package, this one is used for UI synchronization, but with the Windows Forms message loop instead of the XAML-specific dispatcher. Only available for .NET 4.0 and .NET 4.5 projects.
  • Rx-Remoting – installs Rx-Main as well as System.Reactive.Runtime.Remoting. Use this package to get access to the Remotable extension method that can be used to expose an observable sequence over .NET Remoting. Only available on .NET 4.0 and .NET 4.5 projects.
  • Rx-Providers – installs Rx-Main as well as System.Reactive.Providers. This is where the Qbservable mirror image of the System.Reactive.Linq API lives, allowing creation of query providers that translate event stream queries from expression trees to target query languages.
  • Rx-WinRT – installs Rx-Main as well as System.Reactive.WindowsRuntime. If you need to bridge with the IAsyncInfo family of interfaces in Windows Runtime, this is the additional package you need. Only available for Windows Store apps projects.
  • Rx-WindowsStore – equivalent to the Extension SDK, including all assemblies that are tailored for use with Windows Store app projects. Besides the Rx-Xaml package, this also installs Rx-WindowsRuntime, and transitively includes Rx-Main.
  • Rx-Testing – provides access to the testing library, used for writing unit tests for reactive queries using virtual time scheduling. Integrates with the test framework in Visual Studio.

In case you need fine grained control over the lowest layers of the Rx stack, you can also use Rx-Interfaces, Rx-Core, Rx-Linq, and Rx-PlatformServices directly. This is only recommended for advanced scenarios where you don’t need enlightenments, for example when writing a library on top of (part of) Rx.

The screenshot below shows the experience of using NuGet to include Rx-Xaml in a WPF project. Needless to say, this experience is completely analogous in other project types:

image

Search for Rx-Xaml in the search box. Notice the dependencies listed on the right.

image

After resolving and expanding the dependencies, NuGet asks to accept the license. Notice how the Rx-PlatformServices package was included as well, which will ensure Rx performance is optimal for the target platform (here .NET 4.5).

image

Finally, we end up with the required assemblies referenced in the project:

image

And you’re ready to start playing with Rx!

Intermezzo – What about the “Experimental Release”?

Historically, we released Rx at two difference cadences. Before hitting v1.0 RTM, we did a lot of experimentation to land the final design for the core API of Rx. During this process, quite a few semi-baked ideas were introduced in the API surface. By the time we release Rx v1.0 RTM, we had to find a place for those APIs that we were still noodling around with. This is what become known as the Experimental Release.

The model for the Experimental Release was to ship the whole of Rx as a separate “dot” release: v1.0.* was the Stable Release and v1.x.* was the Experimental Release. While this approach worked well, it had a number of drawbacks:

  • To use the Experimental Release, on had to toss out references to the Stable Release and replace all binaries with experimental ones. Doing so is a painful process, also involving the change of NuGet package names to Rx_Experimental (at the time, there was no semantic versioning).
  • With the above, the support for the product also vanished when using the Experimental Release, even though the experimental functionality was largely additive on top of the stable API surface. The wholesale binary replacement didn’t reflect the additive nature at all.

Because a picture is worth a thousands words, here’s an illustration of this model (omitting a few other experimental releases):

image

One of the reasons we went with this approach was to make sure functionality migrating from experimental to stable didn’t break as it moved up. How could that happen? Well, if you have a static method – say for an observable sequence generator method - that’s not meant to be invoked as an extension method, defining it on a class called “ObservableEx” isn’t future proof. As the method moves to stable and gets defined on the “Observable” class instead, this breaks existing code that depended on the experimental functionality. Essentially, splitting a class definition across assemblies isn’t supported.

While moving to the Rx v2.0 release, we felt the cost of maintaining two parallel releases far outweighed the name compatibility advantage. Especially given the refactored API and assembly surface, the pain of replacing a whole bunch of assemblies (and hence loosing support) feels like non-justifiable. At the same time, it wasn’t at all clear how to position a v2.0 Beta in the grand scheme of things. Would a Beta Release be an experimental one?

By the time we shipped Rx v2.0 Beta, it became clear we couldn’t drop the experimental API on the floor, as it’d prevent our cutting edge users to migrate from the latest Experimental Release to the v2.0 Beta release. In the picture below, you can see this transition:

image

I’m drawing the assemblies in the Beta Release in purple, to emphasize their blended nature of the original stable (blue) and experimental (orange/red) functionality we inherited directly from the latest v1.1 build. Nothing here changed in the Release Candidate stage, where we still had all of the what-used-to-be experimental functionality in the product. We left all of this functionality marked with an [Experimental] attribute, so users could keep track of what was still not considered to be fully baked.

Note: For Beta and RC we used NuGet’s semantic versioning feature. We will continue to ship pre-release software using this capability. We consider pre-release builds to be early previews of what we plan to ship for a next major release. Experimental functionality – as discussed below – is more unstable with no promises made yet, and we won’t use the terminology of Beta, Release Candidate, etc. for this going forward.

For RTM, we revisited the list of experimental APIs and decided to refactor what was left as truly experimental into a System.Reactive.Experimental assembly, which is only available through NuGet as the Rx-Experimental package. This allows us to ship frequently as we have new experiments we feel our users may be interested in, without having to worry about complex test matrices for the SDK installer, VSIX packages, etc. The new picture looks as follows:

image

The System.Reactive.Experimental assembly extends all of the Rx APIs (here only showing four assemblies, in reality the experimental library may also extend the capabilities in System.Reactive.Windows.Threading, etc.) and “sits around” all of the stable assemblies as an additive set of APIs. You can continue to run the stable product assemblies, combining them with one single experimental one, rather than having to replace all of Rx wholesale. With this, we can provide better support as we know the heart of Rx was unmodified despite the addition of an experimental layer.

Going forward, the System.Reactive.Experimental assembly will continue to live its own life, moving independently from the stable core of Rx. Today, together with the Rx v2.0 RTM stable set of assemblies, we also shipped the first version of System.Reactive.Experimental. Currently, both have version numbers that are in sync (v2.0.20814), but in the future you’ll see the experimental assembly moving forward independently.

For a next major release of Rx (no promises on timing in this post, though), some of the experimental functionality may promote to that release’s Beta to make its way to the release’s RTM stage. Once a feature enters the major release train, it’s meant to ship eventually in the stable core. Some experimental stuff may stay experimental forever though.

So, what about compatibility for API member names? Quite simply, we don’t make any guarantees that functionality in experimental will work as-is when (if ever) it moves to the stable API. For example, extra query operators in System.Reactive.Experimental are defined on a static class called ObservableEx (where “Ex” stands for “Experimental” and not “Extensions”), paired with QbservableEx for query provider support. Both classes live in the System.Reactive.Linq namespace just like the stable querying API in the System.Reactive.Linq assembly, so all of this functionality blends in nicely. (You can still recognize such operators by looking for the [Experimental] attribute annotation, which could also be used to write tooling to analyze your use of experimental unstable functionality.)

Because a lot of those experimental operators are defined as extension methods, an eventual move to the stable assemblies won’t cause breakages. However, for static methods that can only be invoked using static method invocation syntax, there will be a source-level compatibility break, requiring you to substitute uses of ObservableEx for Observable.

As we prepared for this split, we took the opportunity to promote a few operators to the stable API. One set of such methods are the “imperative operators”, such as “If”, “Case”, “DoWhile”, etc. We’ve seen those being used quite a bit (surprisingly to some extent) and we shipped those in the ROM of Windows Phone 7 before. Considering both those points, and given that their functionality is well-defined and no longer considered “experimental”, we went ahead and polished those (including performance-related work) to put them straight on Observable in the stable API. Not doing so would require them to move to ObservableEx, impairing migration for Windows Phone 7 users from the Rx version in the ROM to the Rx v2.0 release.

The list of experimental APIs for the initial Rx v2.0 System.Reactive.Experimental is rather small:

  • Create for use with iterators (largely redundant due to the introduction of the new async features)
  • Expand to recursively expand a sequence (potentially leading to unbounded concurrency if not used carefully)
  • ForkJoin which can be replaced with composition of CombineLatest and LastAsync
  • Let for trivial observable bindings (not preventing duplication of side-effects, hence quite dangerous)
  • ManySelect, the “co-monadic bind operator” which no-one really understood
  • ToListObservable which was introduced to be paired up with the Create on the top of the list (and in a lot of cases ToList is better anyway)

Option 3 – Installing the Extension SDK from the Visual Studio Gallery

While discussion Option 1, using the Rx SDK MSI, you already saw the concept of Extension SDKs. One additional way to get the Rx v2.0 Extension SDK for Windows Store apps is to go straight to the Tools, Extensions and Updates menu in Visual Studio 2012 and navigate to the Visual Studio Gallery, Tools, Extension SDK section on the left. In there, you’ll find Reactive Extensions listed as well:

image

If you haven’t installed the Rx SDK yet, this window provides you with an option to install the Extension SDK. After completing this step, you can simply include Rx in a Windows Store app project by the steps outlined before: simply go to the Add Reference option and navigate to Windows, Extensions on the left of the Reference Manager dialog. Simply mark the checkbox next to the Reactive Extensions entry and you’re done.

 

We hope you’ll enjoy Rx v2.0! Stay tuned to this blog for more posts (in the regular font again, I promise) about various Rx v2.0 features and improvements.

 

Bart J.F. De Smet
Senior SDE – Cloud Programmability Team

Comments

  • Anonymous
    August 15, 2012
    Why oh why all of the post is in Comic Sans? It's kind of painful to read.

  • Anonymous
    August 15, 2012
    @13xforever - To participate in the celebration of the discovery of the Higgs boson.

  • Anonymous
    August 15, 2012
    The comment has been removed

  • Anonymous
    August 15, 2012
    Kudos to the team. Current system upgraded from Beta with no code changes.

  • Anonymous
    August 16, 2012
    I just looooovvvveeee Comic Sans... :-)

  • Anonymous
    August 20, 2012
    use Readability/Pocket to read this in a civilised font ;) Good stuff though Bart, looking forward to getting this release in

  • Anonymous
    August 23, 2012
    I was attempting to follow the article Curing the asynchronous blues with the Reactive Extensions for .NET but it seems it is out of date?  Are there any plans to release updated tutorials and walkthrus so I can figure out how to best make use of this?

  • Anonymous
    August 28, 2012
    Arrived here after reading that you have improved exception handling in version 2. Is there now a way to catch exceptions thrown in the Dispose method when the factory built instance is disposed of by Observable.Using ?

  • Anonymous
    August 29, 2012
    Sorry, this is a dumb question. I notice that ForkJoin is not in the Rx 2.0 code. I believe this was available in the past as part of a 1.x Experimental release. Is there a 2.0 Experimental release which has it? Or maybe it's in the RTM, just hidden in some other assembly that I haven't looked at? Thanks

  • Anonymous
    August 29, 2012
    Ugh, nevermind. I see the Nuget info above. I will try that.

  • Anonymous
    September 01, 2012
    Good job :) Any eta on RX.JS?  and can we at last get normal, not minified code. Or at least full test suit if code not ready for being published. Thanks.

  • Anonymous
    September 03, 2012
    So it seems it's just recently been updated to 2.0.1 (2.0.20823). Any change notes?

  • Anonymous
    September 04, 2012
    @Joe - We're planning on updating documentation at some point; sorry for the inconvenience. Feel free to post questions to social.msdn.microsoft.com/.../threads in the meantime.

  • Anonymous
    September 04, 2012
    @Huw - Exceptions during the Dispose phase will continue to propagate as they did before. In the case of Using, that's either when the subscription is disposed (so the caller can catch it), or during OnError or OnCompleted operations, in which case the exception can be caught on the originating scheduler using the new Catch extension method. If you have a specific scenario where this causes challenges, feel free to bring it up on social.msdn.microsoft.com/.../threads.

  • Anonymous
    September 04, 2012
    @ngm - The new experimental release can be found in System.Reactive.Experimental as a complementary assembly (see info above). The corresponding NuGet package is Rx-Experimental. (It seems you already figured it out, but just making sure there's some info here for others with the same question reading the comments.)

  • Anonymous
    September 04, 2012
    @Sla - We're still working on getting RxJS v2.0 out the door, but it should take too long anymore.

  • Anonymous
    September 04, 2012
    @Maximilian - The update released on 8/23 addresses a bug in some of the scheduler infrastructure. Minor builds may be released periodically as patches, but won't introduce new functionality and will be fully compatible with the original 8/14 RTM build. (If you're using NuGet, an update to the latest build should be easy.)

  • Anonymous
    September 16, 2012
    >Secondly, the refactoring of Rx v2.0 into a Portable Library based core and platform-specific assemblies for “.NET Framework 4.5” and “.NET for Windows Store apps” (used by Windows 8 XAML applications) is reflected in the feature tree as well. We’ll come back to this in a bit. And what about Silverlight 5 ? Many things are the same in SL5, WPF, WindowsStore

  • Anonymous
    September 17, 2012
    @Anton - We can't achieve portability that includes support for Silverlight 5. The problem is that more than just "many things" have to be the same across all platforms. Unfortunately, Silverlight doesn't have the IObservable<T> and IObserver<T> interfaces built-in, so this prevents us from including it in the portable build of Rx. We'll continue to expand the reach of the portable build of Rx, e.g. by adding Windows Phone 8 to it, but for Silverlight you'll have to use the Silverlight-specific build of Rx.