Skip to content

Conversation

@nohwnd
Copy link
Member

@nohwnd nohwnd commented Dec 8, 2025

Fix #7066

Copy link
Member

@Youssef1313 Youssef1313 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm concerned about this change. The actual TFM is usually present in the path of the assembly. Reporting the actual running runtime here is an additional piece of info we don't want to lose.

This also just caught a bug in .NET 11 insertion today. #7154 (comment)

That bug would have been masked if we report the target framework.

@bradwilson
Copy link

bradwilson commented Jan 13, 2026

The original issue was a nitpick for me, so I don't have a feeling either way.

That said, I have two thoughts:

  • First, if it's supposed to be "what we're running on", why doesn't it says net481? AFAIK, anybody with a fully patched OS should have .NET Framework 4.8.1, and not 4.8, right? (For me, for sure at least, since I'm on latest patched Windows 11 25H2.)

  • Second, the user should know what version of .NET Framework they targeted, presumably if for no other reason than by the path, so "knowing" that .NET Framework 4.8 (or 4.8.1) is running in 4.7.2 "emulation" mode probably doesn't matter that much.

The .NET case is interesting. I wasn't aware that you could run something with dotnet test that targeted one framework, but run it on another framework. I assumed it would only run on the one you built on (or fail because it was missing), rather than just "upgrade". Maybe the aforementioned .NET 11 insertion is a new feature...?

Either way, this is just me collecting information, and it doesn't change my mind that since this is a nitpick, taking away valuable information (like discovering your .NET 10 tests were mysteriously running on .NET 11) seems more valuable than my nitpick.

@Youssef1313
Copy link
Member

@bradwilson

Interesting, for 4.8.1 we should display the full thing:

https://github.com/dotnet/sdk/blob/de50305357a7020997e543e036dfe29ded1832c7/src/Cli/dotnet/Commands/Test/MTP/Terminal/TargetFrameworkParser.cs#L43-L46

Can you double check what RuntimeInformation.FrameworkDescription has for your case?

For what happened in .NET 11, it's because .NET 11 SDK used was in an intermediate state and wasn't fully correct. Putting aside that bug, it's still possible that you can run with a newer runtime if you specify DOTNET_ROLL_FORWARD, or if you alter runtimeconfig.json manually, or if you explicitly run with dotnet exec --runtimeconfig path/to/custom/runtimeconfigjson, or dotnet exec --roll-forward, or dotnet exec --fx-version.

@bradwilson
Copy link

image

@bradwilson
Copy link

bradwilson commented Jan 13, 2026

Based on the linked code, I'm not surprised by net48, since my patch is 9221.0, which doesn't start with 1. (The code appears to assume the printed version would be .NET Framework 4.8.1.)

Also, I tried using target frameworks net48 and net481 and none of those changed the results.

@Evangelink
Copy link
Member

Another option would be to change the format of the display when TFM != actual runtime. Here are some first ideas:

  • (net10.0->net11.0|x64)
  • (net10.0|x64; runtime net11.0)
  • (net11.0|x64; tfm net10.0)
  • (TFM: net10.0 | Runtime: net11.0/x64)

@nohwnd
Copy link
Member Author

nohwnd commented Jan 14, 2026

To me one of the problems is that users state their desired target framework in the project and use that as identifier for that dll when multitargeting. So showing the runtime version makes it harder to know which dll was executed. (On the other hand we on purpose 'lie' about the architecture where it would most often show AnyCPU because that is what we detect from the dll.)

I think a good compromise is to show the build time and run time information once in the console, and then use the mix of real architecture + desired tfm as the identifiers in the rest of the places in the console.

This gives the ability to see both information if you look for it a little, without being overly in your face with the info that you are not normally used to seeing.

This is because:

The full runtime version will almost always be different from the TFM, we could show only when the major and minor versions differ, but then we are doing additional assumptions on the (currently) default Minor roll forward policy. It will also always show for users who use less strict roll forward policy.

It will show almost always for .NET Framework, unless you target the latest. And the versions will not look familiar, like like net489 (4.8.9323.0).

It also helps with being consistent with architecture, where the build time architecture is often AnyCPU, but we don't show that because that information is not useful to identify which dll is which, or how it ran, so we show the effective dll determined by the apphost, or dotnet muxer.

With architecture the issue is of course much smaller, because if the dll targets specific architecture, it will fail to run with the incorrect executable.

@bradwilson
Copy link

I think a good compromise is to show the build time and run time information once in the console

We show a mix of these in the header, but all with a focus for value on understanding the runtime environment:

xUnit.net v3 Console Runner v4.0.0-pre.24-dev+c9a8f61791 [net472/AnyCPU] (64-bit .NET Framework 4.8.9221.0)
xUnit.net v3 Console Runner v4.0.0-pre.24-dev+c9a8f61791 [native/win-x64]

Inside the parenthesis, we show the runtime (and bitness) for the .NET Framework build, but no runtime information for Native AOT builds (since there isn't one, at least as far as the user is concerned; it can only run out-of-process v3 projects).

Inside the square brackets we show what we built for, which is important information for .NET Framework when running v1/v2 tests, since those test projects load in-process. They inherit attributes of that; if we built for .NET 4.7.2, even if you're running with 4.8 or 4.8.1, you're getting 4.7.2 behaviors/features, since the runner's .config file is the one that matters. This is also why we ship versions for 4.7.2, 4.8, and 4.8.1, matrixed with AnyCPU and x86.

It's definitely helped in the past diagnose issues. It was quite the distribution bloat, though, shipping two versions for every .NET Framework from 4.5.2 to 4.8.1 with v2. 😂

@bradwilson
Copy link

It never occurred to me to wonder whether there was .NET Framework on WOA (and whether that "64-bit" should become something more like "x64" vs. "arm64"). I don't think I've ever had a WOA machine in my possession. 😄

@bradwilson
Copy link

net489

I had forgotten all about the brief period of seeing net489 in dotnet test. 😂

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Nitpick: dotnet test with MTP shows incorrect target framework version

5 participants