Add explicit PackageReferences for transitive Microsoft.Extensions.* …#5211
Add explicit PackageReferences for transitive Microsoft.Extensions.* …#5211DrewScoggins wants to merge 5 commits intodotnet:mainfrom
Conversation
…abstractions For .NET 10+, NuGet package pruning removes transitive Microsoft.Extensions.* abstractions (Logging.Abstractions, DependencyInjection.Abstractions, Options, Primitives) from project.assets.json because they are in-band in Microsoft.AspNetCore.App. Without them, the build fails with CS0246 for types like ILogger, IChangeToken, ObjectFactory, StringSegment, etc. Disabling pruning via RestoreEnablePackagePruning=false (PR #5209) only preserves DIRECT PackageReferences. Transitive prunable deps are still removed. Add them as explicit PackageReferences so they remain app-local for BenchmarkDotNet's corerun toolchain (which targets a Microsoft.NETCore.App CoreRoot that does not include the AspNetCore.App shared framework). Also re-enable Microsoft.Extensions.Primitives for net10+ (PR #5196 wrongly removed it assuming it was in NETCore.App; it is actually in AspNetCore.App). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Same root cause: NuGet pruning removes this transitive dep on net10+, causing CS0246 for IConfiguration in ConfigurationBinderBenchmarks. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Same root cause: NuGet pruning removes this transitive dep on net10+, causing CS0012/CS0246 for ICacheEntry and IMemoryCache. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 1 out of 1 changed files in this pull request and generated 1 comment.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| (Logging.Abstractions, DependencyInjection.Abstractions, Options) from the resolution graph | ||
| because they are in-band in Microsoft.AspNetCore.App. We need them as direct PackageReferences | ||
| so they remain app-local for BenchmarkDotNet's corerun toolchain (which targets a |
There was a problem hiding this comment.
The comment lists only Logging.Abstractions/DependencyInjection.Abstractions/Options, but this ItemGroup also adds Caching.Abstractions and Configuration.Abstractions. Update the comment to reflect the full set of explicit abstractions being added (or clarify why those two are included).
| (Logging.Abstractions, DependencyInjection.Abstractions, Options) from the resolution graph | |
| because they are in-band in Microsoft.AspNetCore.App. We need them as direct PackageReferences | |
| so they remain app-local for BenchmarkDotNet's corerun toolchain (which targets a | |
| (Caching.Abstractions, Configuration.Abstractions, Logging.Abstractions, | |
| DependencyInjection.Abstractions, Options) from the resolution graph because they are | |
| in-band in Microsoft.AspNetCore.App. We need them as direct PackageReferences so they | |
| remain app-local for BenchmarkDotNet's corerun toolchain (which targets a |
Write an empty global.json at the workspace root (parent of the perf repo) before invoking dotnet-install. This stops the SDK resolver's upward walk from finding dotnet/runtime's global.json, which contains a 'paths' entry pointing at a '.dotnet' directory holding an older SDK than the one perf installs into tools/dotnet/x64. Without this shield, ci_setup.py's 'dotnet --info' resolves to the wrong SDK and propagates an outdated DOTNET_VERSION to Helix work items, breaking builds on test machines whose ref pack predates recent runtime API changes (e.g. the Sve API rename). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Writing {} broke arcade's bootstrap because it requires tools.dotnet to be present in global.json. Instead, parse the upstream global.json and remove only the sdk.paths field, preserving all other keys.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| <!-- For .NET 10+, NuGet package pruning removes transitive Microsoft.Extensions.* abstractions | ||
| (Logging.Abstractions, DependencyInjection.Abstractions, Options) from the resolution graph | ||
| because they are in-band in Microsoft.AspNetCore.App. We need them as direct PackageReferences | ||
| so they remain app-local for BenchmarkDotNet's corerun toolchain (which targets a | ||
| Microsoft.NETCore.App CoreRoot that does not include the AspNetCore.App shared framework). --> |
There was a problem hiding this comment.
The new explanatory comment lists only Logging.Abstractions/DependencyInjection.Abstractions/Options, but this ItemGroup also adds Caching.Abstractions and Configuration.Abstractions. Please update the comment to reflect the full set of direct PackageReferences being added (or make the wording generic) so it doesn’t become misleading over time.
| <!-- For .NET 10+, NuGet package pruning removes transitive Microsoft.Extensions.* abstractions | |
| (Logging.Abstractions, DependencyInjection.Abstractions, Options) from the resolution graph | |
| because they are in-band in Microsoft.AspNetCore.App. We need them as direct PackageReferences | |
| so they remain app-local for BenchmarkDotNet's corerun toolchain (which targets a | |
| Microsoft.NETCore.App CoreRoot that does not include the AspNetCore.App shared framework). --> | |
| <!-- For .NET 10+, NuGet package pruning removes transitive Microsoft.Extensions.* packages | |
| from the resolution graph because they are in-band in Microsoft.AspNetCore.App. We need | |
| these abstractions as direct PackageReferences so they remain app-local for BenchmarkDotNet's | |
| corerun toolchain (which targets a Microsoft.NETCore.App CoreRoot that does not include the | |
| AspNetCore.App shared framework). --> |
| # Shield subsequent `dotnet` invocations (e.g. `dotnet --info` in ci_setup.py) | ||
| # from picking up an unrelated repo's global.json `paths` entry during the | ||
| # SDK resolver's upward walk. In particular, dotnet/runtime's global.json | ||
| # contains a `paths` entry that points the resolver at a `.dotnet` directory | ||
| # installed by arcade -- which can hold an SDK older than the one the perf | ||
| # scripts just installed into install_dir. We rewrite the upstream | ||
| # global.json with the `sdk.paths` field removed, preserving all other | ||
| # keys (notably `tools.dotnet`, which arcade's bootstrap requires to be | ||
| # present), letting the perf-installed SDK win via standard `$host$` | ||
| # resolution while keeping unrelated tooling functional. | ||
| workspace_root = path.abspath(path.join(get_repo_root_path(), '..')) | ||
| shield_global_json = path.join(workspace_root, 'global.json') | ||
| try: | ||
| if path.exists(shield_global_json): | ||
| with open(shield_global_json, 'r') as f: | ||
| shield_data = json.load(f) | ||
| sdk_section = shield_data.get('sdk') | ||
| if isinstance(sdk_section, dict) and 'paths' in sdk_section: | ||
| removed_paths = sdk_section.pop('paths') | ||
| with open(shield_global_json, 'w') as f: | ||
| json.dump(shield_data, f, indent=2) | ||
| f.write('\n') | ||
| getLogger().info( | ||
| "Stripped sdk.paths=%s from %s to shield SDK resolver " | ||
| "from an unrelated repo's global.json", | ||
| removed_paths, shield_global_json) | ||
| except (OSError, ValueError) as ex: | ||
| getLogger().warning( | ||
| "Could not shield global.json at %s: %s", shield_global_json, ex) |
There was a problem hiding this comment.
This code rewrites ../global.json (parent of the repo) in-place, which can unexpectedly mutate files outside this repo (e.g., a developer’s workspace root) and can leave the workspace dirty or break subsequent builds that rely on sdk.paths. Instead of editing an external global.json, prefer scoping dotnet invocations to the perf repo by setting the working directory for subsequent RunCommand(...).run(...) calls (notably dotnet --info) to get_repo_root_path(), so the resolver picks up this repo’s global.json without touching parent directories. If you keep this approach, it should at least be opt-in and/or restore the original file after the run.
…abstractions
For .NET 10+, NuGet package pruning removes transitive Microsoft.Extensions.* abstractions (Logging.Abstractions, DependencyInjection.Abstractions, Options, Primitives) from project.assets.json because they are in-band in Microsoft.AspNetCore.App. Without them, the build fails with CS0246 for types like ILogger, IChangeToken, ObjectFactory, StringSegment, etc.
Disabling pruning via RestoreEnablePackagePruning=false (PR #5209) only preserves DIRECT PackageReferences. Transitive prunable deps are still removed. Add them as explicit PackageReferences so they remain app-local for BenchmarkDotNet's corerun toolchain (which targets a Microsoft.NETCore.App CoreRoot that does not include the AspNetCore.App shared framework).
Also re-enable Microsoft.Extensions.Primitives for net10+ (PR #5196 wrongly removed it assuming it was in NETCore.App; it is actually in AspNetCore.App).