dotnet / dotnet/roslyn

.NET SDK 10.0.1xx design-time builds of net8.0-targeted projects resolve zero framework references (silent skeleton compilations under MSBuildWorkspace)

Open
#84,510 2 comments 0 reactions 1 assignee Claimed by @jasonmalinowski View on GitHub
Area-Analyzers Bug
Dominant language
C#
Stars
20.7k
Forks
4.3k
PR merge metrics
PR metrics pending

Description

## Description

When a project targeting `net8.0` is loaded through `Microsoft.CodeAnalysis.MSBuild.MSBuildWorkspace` (Roslyn 5.6.0) and the target's `global.json` resolves a **10.0.1xx-band** SDK, the design-time build produces a compilation with **no framework references at all** — only explicit `PackageReference` assemblies survive. `System.String` does not resolve; every cross-assembly type binds as an error type; generated `AssemblyInfo` content (version stamp, `InternalsVisibleTo` attributes from msbuild items) is absent. The load reports **zero `WorkspaceFailed` events**, so consumers receive silently corrupt semantics.

The same projects, with the same restored assets, load correctly when the target resolves a **10.0.2xx** SDK.

## Repro (6 files)

`global.json`:
```json
{ "sdk": { "version": "10.0.109", "rollForward": "patch" } }
```

`LibMulti/LibMulti.csproj`:
```xml


net8.0;net10.0
enable



```

`LibMulti/Secret.cs`:
```csharp
namespace LibMulti;

internal sealed class Secret
{
public string Name { get; init; } = "";
}
```

`LibSingle8/LibSingle8.csproj` (single-TFM — shows it is not specific to multi-TFM inner builds):
```xml


net8.0
enable

```

`ConsumerMini/ConsumerMini.csproj`:
```xml


Exe
net10.0
enable



```

`ConsumerMini/Program.cs`:
```csharp
var secret = new LibMulti.Secret { Name = "x" };
System.Console.WriteLine(secret.Name);
```

Loader (net10.0 console app referencing `Microsoft.Build.Locator` 1.11.2, `Microsoft.CodeAnalysis.CSharp.Workspaces` 5.6.0, `Microsoft.CodeAnalysis.Workspaces.MSBuild` 5.6.0, MSBuild refs `ExcludeAssets="runtime"`):
```csharp
MSBuildLocator.RegisterDefaults();
using var ws = MSBuildWorkspace.Create();
ws.WorkspaceFailed += (_, e) => Console.WriteLine($"FAILED: {e.Diagnostic}");
var consumer = await ws.OpenProjectAsync(@"...\ConsumerMini\ConsumerMini.csproj");
await ws.OpenProjectAsync(@"...\LibSingle8\LibSingle8.csproj");
foreach (var p in ws.CurrentSolution.Projects)
{
var comp = await p.GetCompilationAsync();
Console.WriteLine($"{p.Name}: refs={p.MetadataReferences.Count} " +
$"String={comp!.GetTypeByMetadataName("System.String") is not null} " +
$"version={comp.Assembly.Identity.Version}");
}
```

Steps: `dotnet restore` both leaf projects, run the loader.

## Observed (A/B/A — same projects, same restored assets, only global.json toggled)

| Target-resolved SDK | net8.0 flavors | net10.0 flavors |
|---|---|---|
| 10.0.109 | **0 metadata refs**, assembly version 0.0.0.0, `System.String` unresolvable, IVT attribute constructor args bind as null | healthy |
| 10.0.204 | healthy (163 refs) | healthy |
| 10.0.109 (re-pinned) | broken again | healthy |

Also reproduced with SDK 10.0.106 (an Arcade-bootstrapped copy). Both the multi-TFM net8.0 flavor and the single-TFM net8.0 project show the same skeleton.

## Expected

Either the net8.0 design-time build resolves its framework references (as 10.0.2xx does), or the load surfaces a `WorkspaceFailed` diagnostic. A reference-less compilation with zero failure events is the worst of both.

## What it is not

- Not a missing targeting pack: `Microsoft.NETCore.App.Ref` 8.0.20 and 8.0.27 are installed under `C:\Program Files\dotnet\packs` (8.0.26 in the NuGet cache).
- Not a build break: `dotnet build -f net8.0 --no-restore` of the same project with the same 10.0.1xx SDK succeeds with 0 warnings / 0 errors. Only the design-time load path is affected.

## Real-world impact

Loading dotnet/roslyn's own `Roslyn.slnx` (whose `global.json` pins 10.0.106 + `rollForward: patch`, and whose `Workspaces.MSBuild.Contracts` targets `{net8.0, net472}`) manufactures error types in `Microsoft.CodeAnalysis.LanguageServer`'s compilation — its `InternalsVisibleTo`-granted internals become inaccessible (CS0122 ×20) — which in turn triggers the NullableWalker NRE reported in dotnet/roslyn#84398. With the identical tree resolving a 10.0.2xx SDK, the load is clean (declaration errors 21 → 0) and analysis completes.

## Environment

Windows 11 Pro (10.0.26200); SDKs installed: 9.0.305, 10.0.109, 10.0.204; `Microsoft.CodeAnalysis.Workspaces.MSBuild` 5.6.0; `Microsoft.Build.Locator` 1.11.2.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.