Skip to content

Obsolete AddCSharpApp in favor of AddDotnetProject - #20825

Merged
Mitch Denny (mitchdenny) merged 3 commits into
mainfrom
mitchdenny-stable-csharp-app-apis
Oct 9, 2026
Merged

Mitch Denny (mitchdenny) merged 3 commits into
mainfrom
mitchdenny-stable-csharp-app-apis

Conversation

@mitchdenny

@mitchdenny Mitch Denny (mitchdenny) commented Oct 8, 2026 •

Copy link
Copy Markdown
Member

Description

AddCSharpApp has always been experimental. Replace ASPIRECSHARPAPPS001 with warning-level [Obsolete] attributes directing consumers to AddDotnetProject from Aspire.Hosting.Dotnet.

Both public overloads and the internal addCSharpApp dispatcher are obsolete. The dispatcher directs polyglot callers to addDotnetProject; the TypeScript snapshot now emits @deprecated rather than @experimental. Keep all signatures, return types, defaults, validation, callbacks, path/file/project/directory handling, launch/publish behavior, ATS exports, and export-ignore attributes unchanged.

Remove the old diagnostic suppressions and narrowly suppress CS0618 at retained legacy compatibility consumers in production, playground, and tests. Add regression coverage for warning-level obsoletion, absence of experimental attributes, and ATS deprecation metadata with legacy options/exports preserved. Update XML documentation, the .NET integration's migration guidance, and the related design document. Generated */api/*.cs baselines remain untouched. No other API family is graduated or obsoleted.

Breaking changes

Existing C# AddCSharpApp calls now produce CS0618 instead of the experimental diagnostic. Consumers treating warnings as errors must migrate or explicitly suppress the obsolete warning while retaining the legacy behavior.

Add the Aspire.Hosting.Dotnet integration and use AddDotnetProject / addDotnetProject. It accepts the same kinds of paths, but returns DotnetProjectResource rather than ProjectResource / CSharpAppResource; explicitly typed builders and project-specific customizations may need updating. This PR does not automatically migrate or change the runtime behavior of existing consumers.

User-facing usage

aspire add Aspire.Hosting.Dotnet

C# AppHost:

builder.AddDotnetProject("api", "./api/api.cs");
builder.AddDotnetProject("frontend", "./FileBasedApps.WebFrontEnd/");
builder.AddDotnetProject("inventoryservice", "../InventoryService.cs",
    options => options.LaunchProfileName = "https");

TypeScript AppHost:

await builder.addDotnetProject("api", "./api/api.cs");

Validation

Latest obsoletion commit: commands executed from the repository root. MTP commands exclude quarantined and outerloop tests.

Exact command Result
./restore.sh Passed: 0 warnings/errors.
MSBUILDTERMINALLOGGER=false dotnet test --project tests/Aspire.Hosting.Tests/Aspire.Hosting.Tests.csproj --no-launch-profile -- --filter-class '*.ProjectResourceTests' --filter-not-trait 'quarantined=true' --filter-not-trait 'outerloop=true' Passed: 48 tests, including the new three-method obsoletion check and legacy CSharpApp behavior.
MSBUILDTERMINALLOGGER=false dotnet test --project tests/Aspire.Hosting.Tests/Aspire.Hosting.Tests.csproj --no-launch-profile -- --filter-class '*.DebugSupportExtensionsTests' --filter-not-trait 'quarantined=true' --filter-not-trait 'outerloop=true' Passed: 31 tests, including legacy file-based app debugging.
MSBUILDTERMINALLOGGER=false dotnet test --project tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests.csproj --no-launch-profile -- --filter-class '*.AtsTypeScriptCodeGeneratorTests' --filter-not-trait 'quarantined=true' --filter-not-trait 'outerloop=true' Initial run: 118 passed, 1 expected snapshot mismatch. Reviewed the regenerated snapshot (only three added deprecation annotations), then reran: all 119 passed, including ATS obsoletion metadata and legacy options/export compatibility.
MSBUILDTERMINALLOGGER=false dotnet build src/Aspire.Hosting.Blazor/Aspire.Hosting.Blazor.csproj --no-restore -v:q Passed: 0 warnings/errors.
MSBUILDTERMINALLOGGER=false dotnet build playground/Terminals/Terminals.AppHost/Terminals.AppHost.csproj --no-restore -v:q Passed: 0 warnings/errors.
MSBUILDTERMINALLOGGER=false dotnet build tests/Aspire.Hosting.Dotnet.Tests/Aspire.Hosting.Dotnet.Tests.csproj --no-restore -v:q Passed: 0 warnings/errors.
git diff --check Passed.

Earlier local validation blockers, not rerun for this metadata-only follow-up:

Exact command Result
MSBUILDTERMINALLOGGER=false dotnet test --project tests/Aspire.Hosting.Tests/Aspire.Hosting.Tests.csproj --no-launch-profile -- --filter-method '*CSharpApp*' --filter-not-trait 'quarantined=true' --filter-not-trait 'outerloop=true' 6 passed, 1 failed: CanBuildArchiveFromFileBasedCSharpApp reached dotnet publish, but the local SDK could not create/connect to the CheckForImplicitPackageReferenceOverrides task host (MSB4216/MSB4027 after approximately 5 minutes). Container archive publishing remains unvalidated locally. No publishing implementation changed.
MSBUILDTERMINALLOGGER=false dotnet build playground/FileBasedApps/apphost.cs -v:q /p:SkipDashboardReference=true Failed: CS0103 for DistributedApplication and KnownResourceNames; the standalone file-based AppHost's repository wiring was not resolved.
MSBUILDTERMINALLOGGER=false dotnet build playground/FileBasedApps/apphost.cs -v:q /p:ImportDirectoryBuildProps=true /p:ImportDirectoryBuildTargets=true /p:SkipDashboardReference=true Retry failed with the same CS0103 errors. The terminal playground and production consumer builds above passed.

Fixes # (issue)

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

Remove ASPIRECSHARPAPPS001 from the public overloads and polyglot dispatcher without changing API signatures or runtime behavior. Remove obsolete suppressions and update related documentation and generated TypeScript snapshot metadata.

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

github-actions Bot commented Oct 8, 2026

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 -- 20825

Or

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

@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 8, 2026
@aspire-repo-bot
aspire-repo-bot Bot requested a balanced review from Copilot October 8, 2026 12:33
@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.

🟢 Approval recommended

The narrowly scoped graduation is consistent across source, consumers, documentation, and generated TypeScript output.

0 open findings

What changed in this PR

Graduates AddCSharpApp by removing its experimental diagnostic while preserving existing behavior and API signatures.

Changes:

  • Removes experimental attributes and related warning suppressions.
  • Regenerates the TypeScript snapshot without @experimental.
  • Updates related planning documentation.
File Description
src/​Aspire.Hosting/​ProjectResourceBuilderExtensions.cs Removes experimental attributes from C# app APIs.
src/​Aspire.Hosting.Blazor/​BlazorGatewayExtensions.cs Removes obsolete warning suppression.
tests/​Aspire.Hosting.Tests/​Publishing/​ResourceContainerImageManagerTests.cs Removes obsolete warning suppression.
tests/​Aspire.Hosting.Tests/​ProjectResourceTests.cs Removes obsolete warning suppression.
tests/​Aspire.Hosting.Tests/​DebugSupportExtensionsTests.cs Removes obsolete warning suppression.
tests/​Aspire.Hosting.Dotnet.Tests/​DotnetProjectResourceTests.cs Removes obsolete warning suppression.
tests/​Aspire.Hosting.CodeGeneration.TypeScript.Tests/​Snapshots/​TwoPassScanningGeneratedAspire.verified.ts Records graduated TypeScript APIs.
playground/​Terminals/​Terminals.AppHost/​AppHost.cs Retains only the terminal diagnostic suppression.
playground/​FileBasedApps/​Directory.Build.props Removes the C# app diagnostic suppression.
docs/​plans/​project-v2-csharpprogram-watch.md Describes AddCSharpApp as stable.

🧠 Review effort: Balanced


Give feedback about Copilot approvals in this survey to enter a drawing for a $150 gift card.

@mitchdenny
Mitch Denny (mitchdenny) marked this pull request as draft October 8, 2026 12:46
@github-actions

github-actions Bot commented Oct 8, 2026

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.

Mark both public overloads and the polyglot dispatcher obsolete rather than experimental, retaining their implementations for compatibility. Point consumers to Aspire.Hosting.Dotnet, document migration, and cover warning-level obsoletion and polyglot deprecation metadata.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@mitchdenny Mitch Denny (mitchdenny) added the breaking-change Issue or PR that represents a breaking API or functional change over a prerelease. label Oct 8, 2026
@aspire-repo-bot
aspire-repo-bot Bot requested a balanced review from Copilot October 8, 2026 22:20
@mitchdenny Mitch Denny (mitchdenny) changed the title Graduate AddCSharpApp APIs from experimental Obsolete AddCSharpApp in favor of AddDotnetProject Oct 8, 2026
@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.

🟡 Changes recommended

The design document still contains several statements contradicting the new obsoletion policy.

1 open finding

🧠 Review effort: Balanced

Comment thread docs/plans/project-v2-csharpprogram-watch.md
Distinguish preserved legacy signatures and runtime behavior from changed deprecation metadata in the goal, consumer guidance, work breakdown, and polyglot risks.

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

github-actions Bot commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

Tests selector

50 / 98 PR test projects · 4 PR jobs, from 11 changed files.

Selected PR test projects (50 / 98)

Aspire.Cli.EndToEnd.Tests, Aspire.Hosting.Analyzers.Tests, Aspire.Hosting.Azure.Kubernetes.Tests, Aspire.Hosting.Azure.Kusto.Tests, Aspire.Hosting.Azure.Provisioning.Tests, Aspire.Hosting.Azure.Tests, Aspire.Hosting.Blazor.Tests, Aspire.Hosting.Browsers.Tests, Aspire.Hosting.CodeGeneration.Go.Tests, Aspire.Hosting.CodeGeneration.Java.Tests, Aspire.Hosting.CodeGeneration.Python.Tests, Aspire.Hosting.CodeGeneration.Rust.Tests, Aspire.Hosting.CodeGeneration.TypeScript.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.RemoteHost.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

Selected PR jobs (4)

cli-starter-validation, extension-e2e, polyglot, typescript-api-compat


How these were chosen — grouped by what changed

⚠️ 43 of the 50 selected test projects come from a single change — src/Aspire.Hosting/ProjectResourceBuilderExtensions.cs.

🔧 src/Aspire.Hosting/ProjectResourceBuilderExtensions.cs (changed source)
→ 43 via the project graph

show 43

Aspire.Hosting.Analyzers.Tests (2 hops), Aspire.Hosting.Azure.Kubernetes.Tests (2 hops), Aspire.Hosting.Azure.Kusto.Tests (2 hops), Aspire.Hosting.Azure.Provisioning.Tests (3 hops), Aspire.Hosting.Azure.Tests, Aspire.Hosting.Browsers.Tests (2 hops), Aspire.Hosting.CodeGeneration.Go.Tests, Aspire.Hosting.CodeGeneration.Java.Tests, Aspire.Hosting.CodeGeneration.Python.Tests, Aspire.Hosting.CodeGeneration.Rust.Tests, Aspire.Hosting.Containers.Tests (2 hops), Aspire.Hosting.DevTunnels.Tests (2 hops), Aspire.Hosting.Docker.Tests (2 hops), Aspire.Hosting.DotnetTool.Tests (2 hops), Aspire.Hosting.EntityFrameworkCore.Tests (2 hops), Aspire.Hosting.Foundry.Tests (2 hops), Aspire.Hosting.Garnet.Tests (2 hops), Aspire.Hosting.Go.Tests (2 hops), Aspire.Hosting.Java.Tests (2 hops), Aspire.Hosting.JavaScript.Tests (2 hops), Aspire.Hosting.Kafka.Tests (2 hops), Aspire.Hosting.Keycloak.Tests (2 hops), Aspire.Hosting.Kubernetes.Tests (2 hops), Aspire.Hosting.Maui.Tests, Aspire.Hosting.Milvus.Tests (2 hops), Aspire.Hosting.MongoDB.Tests (2 hops), Aspire.Hosting.MySql.Tests (2 hops), Aspire.Hosting.Nats.Tests (2 hops), Aspire.Hosting.OpenAI.Tests (2 hops), Aspire.Hosting.Oracle.Tests (2 hops), Aspire.Hosting.Orleans.Tests (2 hops), Aspire.Hosting.PostgreSQL.Tests (2 hops), Aspire.Hosting.Python.Tests (2 hops), Aspire.Hosting.Qdrant.Tests (2 hops), Aspire.Hosting.RabbitMQ.Tests (2 hops), Aspire.Hosting.Redis.Tests (2 hops), Aspire.Hosting.RemoteHost.Tests, Aspire.Hosting.Rust.Tests (2 hops), Aspire.Hosting.Seq.Tests (2 hops), Aspire.Hosting.SqlServer.Tests (2 hops), Aspire.Hosting.Testing.Tests (2 hops), Aspire.Hosting.Valkey.Tests (2 hops), Aspire.Hosting.Yarp.Tests (2 hops)

🔧 src/Aspire.Hosting.Blazor/BlazorGatewayExtensions.cs (changed source)
→ 3 directly: Aspire.Cli.EndToEnd.Tests, Aspire.Hosting.Blazor.Tests, Aspire.Hosting.Tests
→ 1 via the project graph: Aspire.Playground.Tests

🧪 tests/Aspire.Hosting.Tests/DebugSupportExtensionsTests.cs (changed test)
→ 1 directly: Aspire.Hosting.Tests
→ 1 via the project graph: Aspire.Hosting.Radius.Tests

📦 affected project Aspire.Hosting.Blazor
→ 1 test: Aspire.Cli.EndToEnd.Tests

📄 playground/FileBasedApps/Directory.Build.props (changed)
→ 1 directly: Aspire.Playground.Tests

📄 playground/FileBasedApps/apphost.cs (changed)
→ 1 directly: Aspire.Playground.Tests

📄 playground/Terminals/Terminals.AppHost/AppHost.cs (changed)
→ 1 directly: Aspire.Playground.Tests

🧪 tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests/AtsTypeScriptCodeGeneratorTests.cs (changed test)
→ 1 directly: Aspire.Hosting.CodeGeneration.TypeScript.Tests

🧪 tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.ts (changed test)
→ 1 directly: Aspire.Hosting.CodeGeneration.TypeScript.Tests

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

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

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

Job reasons

Job Triggered by
cli-starter-validation affected project Aspire.Hosting.JavaScript
extension-e2e • src/Aspire.Hosting.Blazor/BlazorGatewayExtensions.cs, src/Aspire.Hosting/ProjectResourceBuilderExtensions.cs
• affected project Aspire.Hosting.Blazor
polyglot • src/Aspire.Hosting.Blazor/BlazorGatewayExtensions.cs
• affected project Aspire.Hosting.Blazor
• affected project Aspire.Hosting.Azure.Provisioning
typescript-api-compat affected project Aspire.Hosting.Blazor

Selection computed for commit 578d222.

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

This draft changes public warning and polyglot deprecation contracts and explicitly awaits human API and migration review.

0 open findings

1 resolved since last review

🧠 Review effort: Balanced

@github-actions

github-actions Bot commented Oct 8, 2026

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.

@mitchdenny
Mitch Denny (mitchdenny) marked this pull request as ready for review October 8, 2026 23:47
@mitchdenny
Mitch Denny (mitchdenny) enabled auto-merge (squash) October 9, 2026 00:06
Comment thread src/Aspire.Hosting.Blazor/BlazorGatewayExtensions.cs
@mitchdenny
Mitch Denny (mitchdenny) merged commit 6630da5 into main Oct 9, 2026
585 of 588 checks passed
@microsoft-github-policy-service microsoft-github-policy-service Bot added this to the 17.0 milestone Oct 9, 2026
aspire-repo-bot Bot added a commit to microsoft/aspire.dev that referenced this pull request Oct 9, 2026
Documents the breaking change from microsoft/aspire#20825: AddCSharpApp
(and the polyglot addCSharpApp export) is now marked [Obsolete] instead
of [Experimental("ASPIRECSHARPAPPS001")], producing CS0618 instead of
the experimental diagnostic. Adds migration guidance pointing consumers
to AddDotnetProject from the Aspire.Hosting.Dotnet package.

- Added a breaking-change entry to What's new in Aspire 17.0
- Added a Migrating to AddDotnetProject section to the C# file-based
  apps integration page, with updated Aside/limitations text
- Updated the ASPIRECSHARPAPPS001 diagnostic page and the diagnostics
  overview table to note the obsoletion
- Cross-referenced the migration guidance from the .NET host page,
  project-resources comparison, and the existing-app onboarding guide

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

Copy link
Copy Markdown
Contributor

Pull request created: #1853

Generated by PR Documentation Check · copilot · auto · 139.4 AIC · ⌖ 17.1 AIC · ⊞ 20.4K

@aspire-repo-bot

Copy link
Copy Markdown
Contributor

📝 Documentation has been drafted in microsoft/aspire.dev#1853 targeting release/17.0.

Documents the AddCSharpApp → AddDotnetProject obsoletion from #20825 (triggered signals: obsolete_attribute_added, integration_readme_changed, pr_label_breaking_change, pr_body_has_deprecation_marker, pr_body_has_user_facing_section, pr_body_has_cli_flag_mention).

  • Added a breaking-change entry to whats-new/aspire-17.mdx describing the [Obsolete]/CS0618 change and linking to migration guidance.
  • Added a "Migrating to AddDotnetProject" section to integrations/dotnet/csharp-file-based-apps.mdx, updated its Aside banner and limitations list from "Experimental" to "Obsolete".
  • Updated diagnostics/aspirecsharpapps001.mdx and diagnostics/overview.mdx to note the obsoletion and point to the new migration section.
  • Cross-referenced the migration guidance from integrations/frameworks/dotnet/dotnet-host.mdx, integrations/dotnet/project-resources.mdx, and get-started/add-aspire-existing-app.mdx.

Note

This draft PR needs human review before merging.

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

Labels

breaking-change Issue or PR that represents a breaking API or functional change over a prerelease. 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.

4 participants