Skip to content

Preserve package-only AppHost nesting and use starter directory paths - #20958

Draft
David Fowler (davidfowl) wants to merge 2 commits into
mainfrom
copilot/sdk-followups-replacement-20261013-f5ab7e34
Draft

David Fowler (davidfowl) wants to merge 2 commits into
mainfrom
copilot/sdk-followups-replacement-20261013-f5ab7e34

Conversation

@davidfowl

@davidfowl David Fowler (davidfowl) commented Oct 13, 2026 •

Copy link
Copy Markdown
Collaborator

Description

Follow up on merged #20867 for #20933 and #20934, keeping the obsolete SDK functional while preserving the package-only AppHost experience.

  • Supply DynamicFileNesting and DynamicFileNestingEnabled from Aspire.Hosting.AppHost only when IsAspireHost=true. Guard both package and legacy SDK declarations independently so either import order, including preexisting capabilities, produces one of each.
  • Use trailing-slash project-directory paths for the Blazor starter's API/frontend and the React/C# starter's server. Preserve resource names, template substitutions, and chained configuration.
  • Add regression coverage for capability occurrence counts/import orders, project and file-based evaluation fixtures, non-AppHosts, generated starter paths with Redis on/off, and absolute/relative project discovery with/without trailing slashes.
  • Update the SDK migration guide with the package-owned nesting capabilities and supported directory-path form.

AspireOrchestration remains SDK-owned. No repository consumer of that project capability was found; its external Visual Studio impact is unknown and this PR does not invent a fix. No public API, diagnostic suppression, transport default, project-reference compatibility, or central package management behavior changes.

Addresses #20933 and #20934. No companion repository change is required for these source fixes.

Fresh validation and draft limitations

Final head 3d83580ff7ff36361a83ac6609e9c75782b4a305, based on upstream da9f076de522c5638d685e729c2d93ec7d4a0be6. The standalone checks were rerun on that committed head using the repository-pinned .NET SDK 11.0.100-rc.1.26425.128 on Linux.

Check Result
Upstream baseline package-only capability evaluation Reproduced: both nesting capabilities absent
Fresh standalone MSBuild evaluation of rendered source targets Passed 32 SDK-only/package-only/both-import-order/preexisting-capability fixtures and 2 non-AppHost negative fixtures; exact counts asserted
Actual .NET file-based .cs evaluation with source props/rendered targets Passed package-only and both SDK/package import orders; exactly one of each nesting capability, IsAspireHost=true, and PublishAot=false
Fresh template-engine generation from this checkout Passed 8 Blazor/React variants, Redis on/off, ordinary and dotted/spaced names; exact directory strings, trailing slashes, and generated project files checked
Actual source ProjectPathResolver, linked into a dependency-free executable Passed discovery of all 12 generated service project paths
Final-head package build Passed; downloaded exact-head built-nugets, version 17.0.0-pr.20958.g3d83580f
Shipped SDK/AppHost targets from those packages Passed another 32 import-order/preexisting-capability cases, 2 non-AppHost cases, and 3 actual .cs file-based evaluations; exact nesting counts and file-based PublishAot=false asserted
Shipped template pack Passed 8 generated Blazor/React/Redis/name variants, exact package version substitutions, all directory strings and trailing slashes, and source-resolver discovery for all 12 paths
Final-head SDK suites Linux: 92 succeeded, 3 skipped, 0 failed; Windows: 93 succeeded, 2 skipped, 0 failed
Final-head Dotnet suites Linux: 204 succeeded, 0 skipped/failed; Windows: 202 succeeded, 0 skipped/failed
Final-head AppHostTemplateTests Linux: 5 succeeded, 0 skipped/failed, including all 4 new generated-path cases
Final-head BuildAndRunTemplateTests Linux: 5 succeeded, 0 skipped/failed; includes package-only/retained-SDK build/run coverage
Final-head generated Blazor built-in tests Linux: 4 succeeded, 0 skipped/failed. MSTest/NUnit/xUnit generated tests start the AppHost, await healthy webfrontend, and assert HTTP 200 from /; their nested test results are preserved in the job artifact
Final-head CLI C#/React startup and CLI starter validation Linux jobs passed; C#/React checks AppHost startup, not a server HTTP response
Patch hygiene git diff --check passed
Repository SDK test-project build and one standard retry Blocked during restore by NU1900/NU1905; data.nuget.org DNS resolution failed
Local targeted Aspire.Hosting.Sdk.Tests, Aspire.Hosting.Dotnet.Tests, and Aspire.Templates.Tests execution All blocked during restore by the same audit-feed errors; local execution is not claimed

The initial standalone checks use token-rendered source targets. The additional packaged checks use the actual final-head .nupkg targets/props through explicit imports, not a NuGet restore of file-based AppHosts. Both 32-case matrices include simulated FileBasedProgram=true projects and are supplemented by actual .cs file-based SDK evaluation. Standalone template generation skips restore; CI's package-based template suites restore/build/run generated projects. The source-resolver executable is not a substitute for the passing full Dotnet suites.

Remaining limits: Windows/Visual Studio GUI Solution Explorer nesting was not verified; Windows CI capability/build tests are not a GUI pass. The React/C# server's actual HTTP response and file-based #:package restore/startup were not separately exercised. The full outerloop browser suite was excluded by normal PR CI. No launch-profile/transport changes are included or implied. Local restore still fails audit DNS; NuGet audit, warning severity, TLS, and shared DNS settings were not weakened.

The final-head CI run is not wholly green: while the scoped suites above pass, the Windows extension suite failed with EPERM opening a notification-claim file, and AzureFunctionsTests.AddAzureFunctionsProject_WorksWithMultipleProjects failed with TaskCanceledException during StopAsync. Those failures are outside the edited surfaces; baseline status has not been established. Other jobs are still running. Keep this source PR in draft; integrated acceptance and GUI qualification remain separate obligations.

The superseded initial-head run caught a compile error in my new Dotnet test fixture: DistributedApplicationOptions.ProjectDirectory is the supported option, not AppHostDirectory. The second commit corrects it and the final-head Dotnet suites now pass on both platforms. Initial-head results and prior-worker historical evidence are not counted as final-head acceptance.

Checklist

  • Is this feature complete?
    • Yes. Ready to ship.
    • No. Follow-up changes expected.
  • Are you including unit tests for the changes and scenario tests if relevant?
    • Yes
    • No
  • Did you add public API?
    • Yes
      • If yes, did you have an API Review for it?
        • Yes
        • No
      • Did you add <remarks /> and <code /> elements on your triple slash comments?
        • Yes
        • No
    • No
  • Does the change make any security assumptions or guarantees?
    • Yes
      • If yes, have you done a threat model and had a security review?
        • Yes
        • No
    • No

🤖 Posted by Mona (AI Agent)

Cover SDK and package import orders, exact nesting capability counts, generated starter paths, and trailing-slash project discovery.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

Copy link
Copy Markdown
Contributor

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 20958

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 20958"

@github-actions github-actions Bot added the needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners label Oct 13, 2026
@aspire-repo-bot
aspire-repo-bot Bot requested a balanced review from Copilot October 13, 2026 06:44
@github-actions

This comment has been minimized.

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.

🔵 Needs a closer look

The PR remains draft with CI in progress and packaged-target and Visual Studio qualification still incomplete.

0 open findings

What changed in this PR

Preserves Visual Studio file nesting for package-only AppHosts and simplifies generated starter project paths.

Changes:

  • Adds duplicate-safe dynamic file-nesting capabilities.
  • Uses trailing-slash project directories in starter templates.
  • Adds regression coverage and migration guidance.
File Description
src/​Aspire.AppHost.Sdk/​SDK/​Sdk.in.targets Prevents duplicate nesting capabilities.
src/​Aspire.Hosting.AppHost/​build/​Aspire.Hosting.AppHost.in.targets Adds package-owned nesting capabilities.
src/​Aspire.ProjectTemplates/​templates/​aspire-starter/​Aspire-StarterApplication.1.AppHost/​AppHost.cs Uses service directory paths.
src/​Aspire.ProjectTemplates/​templates/​aspire-ts-cs-starter/​Aspire-StarterApplication.1.AppHost/​AppHost.cs Uses the server directory path.
tests/​Aspire.Hosting.Sdk.Tests/​AppHostSdkTargetsTests.cs Covers capabilities and import orders.
tests/​Aspire.Hosting.Dotnet.Tests/​DotnetProjectResourceTests.cs Covers directory-path resolution.
tests/​Aspire.Templates.Tests/​AppHostTemplateTests.cs Verifies generated starter paths.
docs/​migrate-from-apphost-sdk.md Documents nesting and directory paths.

🧠 Review effort: Balanced


💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

Correct the test fixture option identified by fresh Linux and Windows CI compilation.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

Copy link
Copy Markdown
Contributor

Tests selector

46 / 99 PR test projects · 6 PR jobs, from 7 changed files.

Selected PR test projects (46 / 99)

Aspire.Cli.EndToEnd.Tests, Aspire.Hosting.Analyzers.Tests, Aspire.Hosting.Azure.EntraId.Tests, Aspire.Hosting.Azure.Kubernetes.Tests, Aspire.Hosting.Azure.Kusto.Tests, Aspire.Hosting.Azure.Tests, Aspire.Hosting.Blazor.Tests, Aspire.Hosting.Browsers.Tests, Aspire.Hosting.Containers.Tests, Aspire.Hosting.DevTunnels.Tests, Aspire.Hosting.Docker.Tests, Aspire.Hosting.Dotnet.Tests, Aspire.Hosting.DotnetTool.Tests, Aspire.Hosting.EntityFrameworkCore.Tests, Aspire.Hosting.Foundry.Tests, Aspire.Hosting.Garnet.Tests, Aspire.Hosting.Go.Tests, Aspire.Hosting.Java.Tests, Aspire.Hosting.JavaScript.Tests, Aspire.Hosting.Kafka.Tests, Aspire.Hosting.Keycloak.Tests, Aspire.Hosting.Kubernetes.Tests, Aspire.Hosting.Maui.Tests, Aspire.Hosting.Milvus.Tests, Aspire.Hosting.MongoDB.Tests, Aspire.Hosting.MySql.Tests, Aspire.Hosting.Nats.Tests, Aspire.Hosting.OpenAI.Tests, Aspire.Hosting.Oracle.Tests, Aspire.Hosting.Orleans.Tests, Aspire.Hosting.PostgreSQL.Tests, Aspire.Hosting.Python.Tests, Aspire.Hosting.Qdrant.Tests, Aspire.Hosting.RabbitMQ.Tests, Aspire.Hosting.Radius.Tests, Aspire.Hosting.Redis.Tests, Aspire.Hosting.Rust.Tests, Aspire.Hosting.Sdk.Tests, Aspire.Hosting.Seq.Tests, Aspire.Hosting.SqlServer.Tests, Aspire.Hosting.Testing.Tests, Aspire.Hosting.Tests, Aspire.Hosting.Valkey.Tests, Aspire.Hosting.Yarp.Tests, Aspire.Playground.Tests, Aspire.Templates.Tests

Selected PR jobs (6)

cli-starter-validation, extension-e2e, homebrew-installer, polyglot, typescript-api-compat, winget-installer


How these were chosen — grouped by what changed

⚠️ 42 of the 46 selected test projects come from a single change — src/Aspire.AppHost.Sdk/SDK/Sdk.in.targets.

🔧 src/Aspire.AppHost.Sdk/SDK/Sdk.in.targets (changed source)
→ 2 directly: Aspire.Hosting.DotnetTool.Tests, Aspire.Hosting.Sdk.Tests
→ 40 via the project graph

show 40

Aspire.Hosting.Azure.EntraId.Tests, Aspire.Hosting.Azure.Kubernetes.Tests, Aspire.Hosting.Azure.Kusto.Tests, Aspire.Hosting.Azure.Tests, Aspire.Hosting.Blazor.Tests, Aspire.Hosting.Browsers.Tests, Aspire.Hosting.Containers.Tests, Aspire.Hosting.DevTunnels.Tests, Aspire.Hosting.Docker.Tests, Aspire.Hosting.EntityFrameworkCore.Tests, Aspire.Hosting.Foundry.Tests, Aspire.Hosting.Garnet.Tests, Aspire.Hosting.Go.Tests, Aspire.Hosting.Java.Tests, Aspire.Hosting.JavaScript.Tests, Aspire.Hosting.Kafka.Tests, Aspire.Hosting.Keycloak.Tests, Aspire.Hosting.Kubernetes.Tests, Aspire.Hosting.Maui.Tests, Aspire.Hosting.Milvus.Tests, Aspire.Hosting.MongoDB.Tests, Aspire.Hosting.MySql.Tests, Aspire.Hosting.Nats.Tests, Aspire.Hosting.OpenAI.Tests, Aspire.Hosting.Oracle.Tests, Aspire.Hosting.Orleans.Tests, Aspire.Hosting.PostgreSQL.Tests, Aspire.Hosting.Python.Tests, Aspire.Hosting.Qdrant.Tests, Aspire.Hosting.RabbitMQ.Tests, Aspire.Hosting.Radius.Tests, Aspire.Hosting.Redis.Tests, Aspire.Hosting.Rust.Tests, Aspire.Hosting.Seq.Tests, Aspire.Hosting.SqlServer.Tests, Aspire.Hosting.Testing.Tests, Aspire.Hosting.Tests, Aspire.Hosting.Valkey.Tests, Aspire.Hosting.Yarp.Tests, Aspire.Playground.Tests

🔧 src/Aspire.ProjectTemplates/templates/aspire-starter/Aspire-StarterApplication.1.AppHost/AppHost.cs (changed source)
→ 2 directly: Aspire.Cli.EndToEnd.Tests, Aspire.Templates.Tests

🔧 src/Aspire.ProjectTemplates/templates/aspire-ts-cs-starter/Aspire-StarterApplication.1.AppHost/AppHost.cs (changed source)
→ 2 directly: Aspire.Cli.EndToEnd.Tests, Aspire.Templates.Tests

📦 affected project Aspire.AppHost.Sdk
→ 1 test: Aspire.Cli.EndToEnd.Tests

🔧 src/Aspire.Hosting.AppHost/build/Aspire.Hosting.AppHost.in.targets (changed source)
→ 1 via the project graph: Aspire.Hosting.Analyzers.Tests

🧪 tests/Aspire.Hosting.Dotnet.Tests/DotnetProjectResourceTests.cs (changed test)
→ 1 directly: Aspire.Hosting.Dotnet.Tests

🧪 tests/Aspire.Hosting.Sdk.Tests/AppHostSdkTargetsTests.cs (changed test)
→ 1 directly: Aspire.Hosting.Sdk.Tests

🧪 tests/Aspire.Templates.Tests/AppHostTemplateTests.cs (changed test)
→ 1 directly: Aspire.Templates.Tests

Job reasons

Job Triggered by
cli-starter-validation • src/Aspire.AppHost.Sdk/SDK/Sdk.in.targets, src/Aspire.ProjectTemplates/templates/aspire-starter/Aspire-StarterApplication.1.AppHost/AppHost.cs
• affected project Aspire.AppHost.Sdk
extension-e2e • src/Aspire.AppHost.Sdk/SDK/Sdk.in.targets, src/Aspire.Hosting.AppHost/build/Aspire.Hosting.AppHost.in.targets
• affected project Aspire.AppHost.Sdk
homebrew-installer src/Aspire.ProjectTemplates/templates/aspire-starter/Aspire-StarterApplication.1.AppHost/AppHost.cs, src/Aspire.ProjectTemplates/templates/aspire-ts-cs-starter/Aspire-StarterApplication.1.AppHost/AppHost.cs
polyglot • src/Aspire.AppHost.Sdk/SDK/Sdk.in.targets
• affected project Aspire.AppHost.Sdk
typescript-api-compat affected project Aspire.Hosting.AppHost
winget-installer src/Aspire.ProjectTemplates/templates/aspire-starter/Aspire-StarterApplication.1.AppHost/AppHost.cs, src/Aspire.ProjectTemplates/templates/aspire-ts-cs-starter/Aspire-StarterApplication.1.AppHost/AppHost.cs

Selection computed for commit 3d83580.

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.

🔵 Needs a closer look

The source-reading regression lacks CI trigger-map routing, while final packaged and Visual Studio validation remains pending.

0 open findings

Previously missed (1)

In code that hasn't changed since last review

Medium severity This test reads Aspire.Hosting.AppHost.in.targets directly from the repository, but…

tests/​Aspire.Hosting.Sdk.Tests/​AppHostSdkTargetsTests.cs:56

This test reads Aspire.Hosting.AppHost.in.targets directly from the repository, but eng/github-ci/test-trigger-map.yml does not route src/Aspire.Hosting.AppHost/** changes to test:Aspire.Hosting.Sdk.Tests, and the test project has no ProjectReference to that package. Future edits to the target can therefore skip this regression test. Add a path rule for the consumed AppHost build inputs and focused selector coverage.

🧠 Review effort: Balanced

@github-actions

Copy link
Copy Markdown
Contributor

Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt.

This branch has not been deployed

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

Labels

needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants