Rx.NET v7.0 Now Available
We are pleased to announce the release of a new version of the Reactive Extensions for .NET (Rx.NET). System.Reactive v7.0.0 is now available on NuGet. This release can reduce the size of self-contained deployments by up to 90MB!
What's new?
This release has exactly one new feature: it fixes a long-standing problem that caused some projects to stop using Rx.NET. You could end up with 90MB of unnecessary extra build output if you had a project with both of these characteristics:
- Self-contained deployment (or Native AoT)
- A Windows-specific
<TargetFramework>specifying version 10.0.19041 or later (e.g.net8.0-windows10.0.19041)
In projects like these, adding a reference to System.Reactive would cause a complete copy of the Windows Forms and WPF frameworks to be deployed as part of your application. Without trimming, this would add about 90MB to the output size. Self-contained deployment with trimming enabled was slightly less bad, adding 'just' 47MB. NativeAoT is better still, with growth of about 11MB.
Since System.Reactive.dll is around 1.5MB in size, this inflation was absurd. It was the result of a design decision made many years ago that didn't cause any of these problems at the time. Subsequent changes in the .NET ecosystem have made that decision look regrettable in hindsight.
What does this mean for me?
For most users of Rx.NET, this update will change nothing. In particular, if you aren't building for a Windows-specific target framework (e.g. if you target net10.0) there is no new or changed functionality. We have dropped support for older versions of .NET (.NET 7.0 and before) but Microsoft already stopped supporting those some time ago.
If you build for a Windows-specific target, then this change may affect you. If you were using the WPF, Windows Forms, or Windows Runtime support built into Rx.NET, you will need to add new NuGet package references. (See the next section for details.) If you were not, then you won't need to change anything, and if you are using self-contained deployment you should see the size of your built output dropping dramatically.
Breaking changes
There are three causes of breaking changes in this release:
- we have removed support for out-of-support .NET runtimes (v7.0 and older).
- if your project uses Rx.NET's support for WPF, Windows Forms, UWP, or Windows Runtime, you will get compiler errors after upgrading, and will need to add additional NuGet package references. (This is a compile-time breaking change only.)
- we fixed a bug (#2247) in the nullability of
OfType, which, strictly speaking, is a breaking change; the nullability now correctly reflects the (unchanged) behaviour, so this is as benign a breaking change as we think is possible.
(We saved that last bugfix for this release specifically because it is, strictly speaking, a breaking change, so for semantic versioning purposes, it needed a major version bump.)
Supported .NET versions
Rx 7.0 removes support for .NET 6.0 and .NET 7.0. Those runtimes have already been out of support for some time, but it was possible to use Rx 6.1 with them because it offered net6.0 and net6.0-windows10.0.19041 TFMs. (Rx 7.0 might actually still run on these old runtimes thanks to its netstandard2.0 support, but we do not test this so we do not support it.)
We offer net8.0, net8.0-windows10.0.19041, net472, netstandard2.0, and uap10.0.18362 targets.
We fully support running on .NET 8.0, 9.0 and 10.0. (We don't have a net10.0 target, but that's because there's nothing in net10.0 that requires code that is any different from the net8.0 code.) We will support .NET 11.0 once that ships. (It is likely that this will just mean updating the test suite, but if it turns out that there are any compatibility issues, we will ship an update. But we expect to continue offering the same targets in our NuGet packages.)
UI framework support now in separate packages
The cause of the 'bloat' problem in which System.Reactive could grow your deployable outputs by 90MB was the fact that support for WPF and Windows Forms was built right into the main System.Reactive package. To fix the problem, this functionality is available only through UI-framework-specific packages
System.Reactive.Windows.Formsfor Windows FormsSystem.Reactive.Wpffor WPFSystem.Reactive.WindowsRuntimefor WinRT (e.g., CoreDispatcher) supportSystem.Reactive.Uwpfor UWP
Note that if you have existing code that was relying on these features being built into System.Reactive, we include a Code Analyzer in System.Reactive 7.0 that detects this and tells you exactly which NuGet package you need to be using.
Binary compatibility retained
Although we have removed WPF, Windows Forms and UI-related Windows Runtime support from the public API of System.Reactive, it does in fact remain available at runtime. This is to ensure that upgrading to Rx 7.0 doesn't break older components that were built against Rx 6.1, and which expect that functionality still to be there.
We do this by continuing to ship all the relevant code in the DLLs in the lib folder of the NuGet package. These APIs have been removed only from the ref folder. This is sufficient to prevent the 'bloat' problem while also maximizing binary compatibility.
There's one thing to be aware of: projects using the ancient packages.config mechanism don't recognize the distinction between lib and ref folders—they use the lib folder at compile time as well as runtime. So projects still using that system will continue to be able to use the WPF and Windows Forms features without adding the new package references. We do not recommend this (because we hope, many years from now, to remove that code entirely) and we do not support the use of the old packages.config mechanism with Rx.NET.
Why just this one change?
This was a surprisingly difficult problem to solve. For the full (very complex) details, you can read the 0005-package-split.md ADR, which describes the history that led up to this problem, and all the possible responses we considered.
Since this is a quite significant change in the packaging, we felt it was best to make that the focus of this release. While we have done extensive testing, and have engaged in an extensive consultation period with the community, it's possible that problems will become apparent only after more people start to use it. So we wanted to keep this change separate from anything else.
What's next?
This finally completes the goals we described in the roadmap we published back when endjin first took over maintenance of Rx.NET. That roadmap outlined what we saw as the 'must fix' issues. And although we have shipped a few new features in that time, most of the work has gone into dealing with what was essentially technical debt. We are now free to move onto more exciting work.
We are very much open to community input on what the direction should be for future work. Here are some areas we have in mind:
- Performance, especially:
- Applying a low-allocation philosophy
- Code generation (in other libraries we maintain, we've found code generation to be an extremely effective tool for producing very high performance code, and we have some ideas here)
- Investigate whether we can support
ref-like elements
- Consider outstanding requests for new operators, including
- Providing operators that actually do some of the various things people imagine
Throttleshould do
- Providing operators that actually do some of the various things people imagine
Please try it out
This new 7.0 release of System.Reactive is available on NuGet today. If you're using Rx in your application, please try upgrading. If you have any problems, please file issues at https://github.com/dotnet/reactive/issues. Meanwhile, we hope you enjoy this new version of the Reactive Extensions for .NET.
More Rx content
As well as the two series from Carmel Eve's Rx Operators Deep Dive and Richard Kerslake's Event stream manipulation for Rx with semantic logging, you can find further information here:
- Intro to Rx.NET 3rd Edition (2025)
- Rx playlist (on the endjin YouTube channel)
- Rx 101 Workshop
- Rx talk for the dotnetsheff user group
- https://reaqtive.net/ — a persistent, reliable, distributed stream processing system based on Rx