Skip to content

File-based apps: support legacy artifact behavior - #55970

Merged
jjonescz merged 3 commits into
dotnet:mainfrom
jjonescz:sprint-reuse-artifacts-net10
Sep 4, 2026
Merged

jjonescz merged 3 commits into
dotnet:mainfrom
jjonescz:sprint-reuse-artifacts-net10

Conversation

@jjonescz

Copy link
Copy Markdown
Member

Follow up on #55697.
Needed for MSBuildWorkspace, see dotnet/roslyn#85065.

@jjonescz jjonescz added the Area-run-file Items related to the "dotnet run <file>" effort label Aug 27, 2026
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).
2 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@github-actions

Copy link
Copy Markdown
Contributor

🔴 Build Failure Analysis

Error: RS0051 — Symbol not in declared API

Failing leg: Windows x64 (and likely all other legs)

Root cause: The PR added a new parameter bool useLegacyArtifactsPath = false to VirtualProjectBuilder.WriteProjectFile(...) in VirtualProjectBuilder.cs, but InternalAPI.Unshipped.txt still declares the old signature without that parameter. The Roslyn public-API analyzer (RS0051) requires that every internal API method signature match its declaration file exactly.

The error:

error RS0051: Symbol 'static ...VirtualProjectBuilder.WriteProjectFile(
    ..., string? artifactsPath = null, bool useLegacyArtifactsPath = false,
    bool includeRuntimeConfigInformation = true, ...) -> void'
is not part of the declared API

Fix: Update src/Cli/Microsoft.DotNet.FileBasedPrograms/InternalAPI.Unshipped.txt line 74 to insert bool useLegacyArtifactsPath = false between artifactsPath and includeRuntimeConfigInformation (see inline suggestion).

🤖 Automated content by GitHub Copilot. Generated by the Build Failure Analysis workflow. · 50.2 AIC · ⌖ 7.79 AIC · ⊞ 5.3K · [◷]( · ◷)

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🤖 Automated content by GitHub Copilot. Generated by the Build Failure Analysis workflow. · 50.2 AIC · ⌖ 7.79 AIC · ⊞ 5.3K · ◷

@jjonescz
jjonescz marked this pull request as ready for review August 28, 2026 11:33
@jjonescz
jjonescz requested a review from a team as a code owner August 28, 2026 11:33
Copilot AI lite review requested due to automatic review settings August 28, 2026 11:33
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).
2 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR updates file-based app virtual project generation to preserve older (“legacy”) artifacts behavior when the MSBuild/SDK being used doesn’t recognize the newer file-based artifacts mechanism. This is intended to improve compatibility with external hosts (e.g., MSBuildWorkspace) that may not be running the same SDK/targets as the dotnet CLI.

Changes:

  • Detect when artifacts props are imported but no artifacts layout was selected, and switch to a legacy artifacts-property emission path.
  • Extend VirtualProjectBuilder.WriteProjectFile with a new useLegacyArtifactsPath parameter and emit legacy artifacts-related properties when enabled.
  • Update InternalAPI.Unshipped.txt to reflect the signature change.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
src/Cli/Microsoft.DotNet.FileBasedPrograms/VirtualProjectBuilder.cs Adds legacy-artifacts detection/caching and a new project-file emission mode via useLegacyArtifactsPath.
src/Cli/Microsoft.DotNet.FileBasedPrograms/InternalAPI.Unshipped.txt Updates tracked internal API signature for WriteProjectFile.

@jjonescz

Copy link
Copy Markdown
Member Author

@333fred @RikkiGibson for a review, thanks

@333fred 333fred left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Are there tests for this behavior somewhere?

@jjonescz

jjonescz commented Sep 1, 2026

Copy link
Copy Markdown
Member Author

This is checked on the roslyn side (without this, the CI of dotnet/roslyn#85065 would fail), but I will add explicit tests here too.

@jjonescz
jjonescz requested a review from 333fred September 1, 2026 09:10
@jjonescz

jjonescz commented Sep 3, 2026

Copy link
Copy Markdown
Member Author

@333fred for another look, thanks

@jjonescz
jjonescz merged commit 4d1df05 into dotnet:main Sep 4, 2026
21 checks passed
@jjonescz
jjonescz deleted the sprint-reuse-artifacts-net10 branch September 4, 2026 10:51
slang25 added a commit to slang25/Buildalyzer that referenced this pull request Sep 6, 2026
A file-based app - a single .cs file run with `dotnet run app.cs` - has no
project file, so passing one to GetProject threw on XDocument.Load. Roslyn's
MSBuildWorkspace opens these by generating the project in its build host, which
is not open to us: expanding the file-level directives means evaluating the
project being built up, repeatedly, against a real MSBuild, and the core
library deliberately has no engine. `dotnet msbuild app.cs` is not an
alternative either - only the SDK's own verbs route a .cs file through the
virtual project, and `dotnet build app.cs` rejects the -l: the pipe logger
needs.

So ask the SDK for the project instead, over the same hidden `dotnet run-api`
protocol IDEs use to see behind a file-based program, and build that. The
project is parsed from the XML the SDK hands back, never from disk, so
directives (#:package, #:sdk, #:property) come through evaluated and the whole
IProjectFile surface behind them keeps working. MSBuild is handed a project
path on the command line, though, so the project is written to the path the SDK
would have used - next to the entry point file, which is what Directory.Build
.props, nuget.config and global.json discovery walk up from - for the duration
of each build and removed after, with concurrent per-framework builds sharing
the one file. A project already sitting there is only replaced if it carries
the SDK's FileBasedProgram marker, so an earlier crashed run's leftover is
recoverable and a real project of the user's is never overwritten.

Two version details are worth knowing. The generated project's path is the
SDK's to choose (it became app.cs.csproj during .NET 10, when the response
started reporting it), so it is read from the response and only guessed at the
older convention when absent. And the artifacts properties it emits depend on
the SDK that evaluates it (dotnet/sdk#55970), which is decided before any
BuildEnvironment exists; generation therefore uses the default dotnet, a build
pointed at another one is warned about, and a file-based app always builds
against the .NET SDK rather than .NET Framework MSBuild.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@dotnet-milestone-bot dotnet-milestone-bot Bot added this to the 12.0-preview1 milestone Sep 7, 2026
@jjonescz

Copy link
Copy Markdown
Member Author

/backport to release/11.0.1xx

@github-actions

Copy link
Copy Markdown
Contributor

Started backporting to release/11.0.1xx (link to workflow run)

This branch had an error being deployed

1 failed deployment
copilot-pat-pool — 02dfa56c Deployed Sep 4, 2026 by jjonescz via pre_activation #2901
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area-run-file Items related to the "dotnet run <file>" effort

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants