Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rx.NET 6 preview 1 does not work with net7.0-windows #1889

Closed
JasonWeinzierl opened this issue Mar 11, 2023 · 7 comments · Fixed by #1901
Closed

Rx.NET 6 preview 1 does not work with net7.0-windows #1889

JasonWeinzierl opened this issue Mar 11, 2023 · 7 comments · Fixed by #1901
Assignees
Milestone

Comments

@JasonWeinzierl
Copy link

When installing System.Reactive version 6.0.0-preview.1 either to a project that targets net7.0-windows or to a class library that's referenced by another project targeting net7.0-windows, I get the following error:

The 'System.Reactive' nuget package cannot be used to target 'net7.0-windows'. Target 'net6.0-windows10.0
.19041' or later instead.

Which library version?

6.0.0-preview.1

What are the platform(s), environment(s) and related component version(s)?

Windows 10 22H2 19045.2673

dotnet CLI version 7.0.201

What is the use case or problem?

Applications with an OS-specific TFM (like a windows desktop app)

What is the expected outcome?

.NET 7 apps with an OS-specific TFM using Rx 6 should build successfully

What is the actual outcome?

Build fails

What is the stacktrace of the exception(s) if any?

MSBuild version 17.5.0-preview-23061-01+040e2a90e for .NET
  Determining projects to restore...
  All projects are up-to-date for restore.
C:\Users\{redacted}\.nuget\packages\system.reactive\6.0.0-preview.1\buildTransitive\net6.0-windows7\System.Reactive.targets(
5,5): error : The 'System.Reactive' nuget package cannot be used to target 'net7.0-windows'. Target 'net6.0-windows10.0
.19041' or later instead. [{redacted}\TestRx6Win7\TestRx6Win7.csproj]

Build FAILED.

C:\Users\{redacted}\.nuget\packages\system.reactive\6.0.0-preview.1\buildTransitive\net6.0-windows7\System.Reactive.targets(
5,5): error : The 'System.Reactive' nuget package cannot be used to target 'net7.0-windows'. Target 'net6.0-windows10.0
.19041' or later instead. [{redacted}\TestRx6Win7\TestRx6Win7.csproj]
    0 Warning(s)
    1 Error(s)

Time Elapsed 00:00:00.60

Do you have a code snippet or project that reproduces the problem?

Set up a new console app (using --target-framework-override for the sake of example but the same occurs if you manually change the TFM via Visual Studio or editing the csproj):

dotnet new console -n TestRx6Win7 --target-framework-override net7.0-windows
cd .\TestRx6Win7
dotnet run

Then install Rx 6 preview 1:

dotnet add package System.Reactive -v 6.0.0-preview.1
dotnet build

Build fails with the aforementioned error.

@HowardvanRooijen
Copy link
Collaborator

Thank you!

@idg10
Copy link
Collaborator

idg10 commented Mar 12, 2023

Does setting your <TargetFramework> to net7.0-windows10.0.19041 remove the error?

For reasons that have yet to become clear to us, previous maintainers of Rx found it necessary to put a higher minimum Windows API version in the TFM for the target that supports WPF and Windows Forms. There are a bunch of complex problems here, and in the long run we're aiming to resolve that by putting those framework-specific parts into separate components, so in the long run, if you use System.Reactive from net7.0-windows you'll get the same version as if you'd targetted net7.0. However we won't be doing this in the time frame that we want to get Rx 6.0 out in.

Ideally we'd drop the requirement for 10.0.19041, but until I find out why the previous maintainers put that in, I can't just remove it. So it might be that for 6.0, the best we can do is improve the error message here.

@JasonWeinzierl
Copy link
Author

Yep that fixes the error.

@idg10
Copy link
Collaborator

idg10 commented Mar 13, 2023

OK, so here's a bit more background on why this happened.

Back in November 2020, @dotMorten added this commit: 415d91f

I believe the purpose of that was to address the problem that loads of people building desktop apps were running into: they would add a reference to Rx and then be baffled that UI-framework support (e.g. ObserveOnDispatcher) seemed to be missing. For example, see #1315, #1436, or #1466.

The PR associated with that commit describes how @dotMorten was intending to address this: #1442

The thing I hadn't realised until today is that no version of Rx ever shipped with @dotMorten's change!

I thought that in Rx.NET 6.0 preview.1 I was carefully reproducing the same behaviour Rx has had for the last two and a third years. But I've now realised that I've just given @dotMorten's change its first public outing!

Also, things have moved on a bit since he submitted that change, meaning that my attempt to update the behaviour from .NET 5 to .NET 6 wasn't really sufficient. At the time he wrote that, there was only one version of .NET for which it was relevant: .NET 5. But now, both .NET 6 and .NET 7 have the issue that this change was meant to address, meaning that the error message it produces now needs cater for multiple versions of .NET.

However, I'm now thinking that we probably don't want this feature: I think that it might cause a lot of problems for existing users.

Here's what happens with today's Rx 5.0 package, with a variety of host application TFMs and developer intentions:

App TFM Want WPF/WinForms? Rx TFM Effect
net5.0 No net5.0 App gets the non-WPF/WinForms Rx
net5.0-windows No net5.0 App gets the non-WPF/WinForms Rx
net5.0-windows Yes net5.0 Developer baffled by missing support for WPF/WinForms
net5.0-windows10.0.19041 (or later) No net5.0-windows10.0.19041 App gets the WPF and WinForms functionality whether not it's wanted (which causes horrendous app bloat for some .NET app packaging models); Developer can't choose simply to use the non-WPF/WinForms version
net5.0-windows10.0.19041 (or later) Yes net5.0-windows10.0.19041 App gets the WPF and WinForms functionality

@dotMorten's change was designed to address the 3rd entry in that list, where the developer wants either WPF or Windows Forms features, but hasn't realised that they need to make their app target an OS-version-specific in order to get those features.

Here's the situation after @dotMorten's change:

App TFM Want WPF/WinForms? Rx TFM Effect
net5.0 No net5.0 App gets the non-WPF/WinForms Rx
net5.0-windows No net5.0 Build error telling developer to make their app target net5.0-windows10.0.19041 or later; Developer can't choose simply to use the non-WPF/WinForms version
net5.0-windows Yes net5.0 Build error helpfully telling developer what to do
net5.0-windows10.0.19041 (or later) No net5.0-windows10.0.19041 App gets the WPF and WinForms functionality whether not it's wanted (which causes horrendous app bloat for some .NET app packaging models); Developer can't choose simply to use the non-WPF/WinForms version
net5.0-windows10.0.19041 (or later) Yes net5.0-windows10.0.19041 App gets the WPF and WinForms functionality

So it would fix the problem it aims to fix (3rd row in table). But it creates a new problem visible in row 2. With Rx 5.0 as it is today, developers targeting a Windows-specific TFM for a Windows API version older than 10.0.19041 (note that net5.0-windows is shorthand for net5.0-windows7, and Windows 7 is definitely a lot older than that!) are able to use the version of Rx that doesn't include WPF/Windows Forms support.

@dotMorten's change would remove that capability.

Now this whole situation is a mess. The key issue here is the means by which you determine whether or not you get WPF and/or Windows Forms features. Back in Rx 3 this was determined by your choice of NuGet package references, but since Rx 4.0, it was based on which version of .NET you were targetting. My view is that with hindsight, that decision to move the WPF and Windows Forms functionality into the main System.Reactive component was a mistake, because it means you don't always have control over whether you take a dependency on WPF and Windows Forms. (And for people doing self-contained deployments that can be a disaster: they end up bundling copies of both WPF and Windows Forms in their apps, making their installers tens of megabytes larger than they should be!)

So one of our goals for Rx 7.0 is to revert part of the "great unification" in which Rx 4.0 merged absolutely everything into a single System.Reactive component. Specifically, we want to move UI-framework-specific code back out into UI-framework-specific NuGet components. Want WPF? Add a reference to the the Rx WFP extensions component? Want Windows Forms? Add a reference to the Rx Windows Forms extension components? Don't want either? No problem—just don't ask for them. But this is a significant change, so we're not doing it for Rx 6.0.

So I'm currently thinking that our best bet for now is probably to back out @dotMorten's change because I think the 2nd table above is a worse situation than the first one. The first one is the status quo, so we won't be making anything worse. And I think the change to the 2nd row in the 2nd table could upset a lot of people.

@idg10
Copy link
Collaborator

idg10 commented Mar 31, 2023

The first preview with this change is now up on NuGet as 6.0.0-preview.9.

This gives us the following behaviours if you're on .NET 7 (and just substitute net6.0 for net6.0 in the 1st column to get the .NET 6.0 behaviour:

App TFM Want WPF/WinForms? Rx TFM Effect
net7.0 No net6.0 App gets the non-WPF/WinForms Rx
net7.0-windows No net6.0 App gets the non-WPF/WinForms Rx
net7.0-windows Yes net6.0 Developer baffled by missing support for WPF/WinForms
net7.0-windows10.0.19041 (or later) No net6.0-windows10.0.19041 App gets the WPF and WinForms functionality whether not it's wanted (which causes horrendous app bloat for some .NET app packaging models); Developer can't choose simply to use the non-WPF/WinForms version
net7.0-windows10.0.19041 (or later) Yes net6.0-windows10.0.19041 App gets the WPF and WinForms functionality

@BButner
Copy link

BButner commented Apr 26, 2023

Is there currently any way to target net7.0-windows, include the WPF/WinForms functionality, and not add the windows version on the end?

@idg10
Copy link
Collaborator

idg10 commented May 18, 2023

Is there currently any way to target net7.0-windows, include the WPF/WinForms functionality, and not add the windows version on the end?

No.

For one thing, an OS-specific TFM always implies a version, even if you don't write it explicitly. So net7.0-windows is shorthand for net7.0-windows7. (Yes, Windows 7. The one that went out of support really quite a long time ago.) Similarly, net6.0-windows is shorthand for net6.0-windows7.

Even if we take Rx out of the equation completely, it's not actually possible to specify a Windows-specific TFM without specifying a version number. You might haze specified it implicitly (by not saying the version number in the TFM) but you are nevertheless specifying a version number, even if you didn't realise that you were.

There's a popular misconception that net7.0-windows means "Windows, but I don't care which version." But that's not what it means. For a library it means "I can run on any version of Windows from 7 or later." More subtly, when an application uses that TFM it means "I can use Window-specific libraries but only if they are able to run on Windows 7." (There's an implied "...because I want to be able to run on Windows 7" except in practice that's not a supported runtime scenario. So the actual effect of this is just to constrain which libraries you can use.)

These are really weird statements when you say them out loud—it's hard to believe that anyone deliberately wants to make these very specific statements relating to a very old unsupported version of Windows, but that is what they're doing when they write just net7.0-windows.

So, bearing in mind that you are always specifying a Windows version even if you don't say it out loud. The significance of the version number when it comes to Rx is that the Windows-specific target in Rx has a minimum version number. (I don't actually know why—that was set in a commit that has absolutely no explanation as to why that version number was chosen, the person who wrote it is not responding to enquiries about Rx, and I've not yet managed to work for myself out the logic behind it.) Rx's WPF/Windows Forms functionality doesn't work (or at least, claims not to work) on versions of Windows older than 10.0.19041, and so you don't get to use that functionality unless your code imposes a constraint that it must be running on 10.0.19041 or later.

If you target just net7.0-windows you are saying "I can run on Windows 7", and Rx's WPF/Windows Forms features can't run on Windows 7, and that's why the library is unavailable to you if you use that TFM.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants