Skip to content

Fix Radius container image exports for TypeScript - #21830

Draft
Karol Zadora-Przylecki (karolz-ms) wants to merge 1 commit into
mainfrom
dev/karolz/radius-typescript-exports
Draft

Karol Zadora-Przylecki (karolz-ms) wants to merge 1 commit into
mainfrom
dev/karolz/radius-typescript-exports

Conversation

@karolz-ms

Copy link
Copy Markdown
Contributor

Description

Restores Radius's withContainerImage(image) method on DotnetProjectResource in generated TypeScript AppHosts. Overlapping legacy and generic exports previously caused a collision on CSharpAppResource that removed the generic capability for every target, including modern .NET projects.

Export the generic overload once using the existing Aspire.Hosting.Radius/withContainerImage capability ID, and exclude the legacy overload from ATS discovery. Both public C# overloads and scanner collision policy remain unchanged. Add real-assembly generation/scanning and runtime-dispatch regressions for legacy projects, file-based apps, and modern .NET projects. No new external package dependencies are required.

Fixes #21803

User-facing usage

With the Radius and Dotnet integrations referenced, TypeScript AppHosts can again use:

await builder.addDotnetProject("api", "../Api/Api.csproj")
    .withContainerImage("ghcr.io/myorg/api:v1");

The corresponding C# API is unchanged:

builder.AddDotnetProject("api", "../Api/Api.csproj")
       .WithContainerImage("ghcr.io/myorg/api:v1");

Compatibility

The retained capability now targets and returns IDotnetProgramResource in ATS metadata, while generated methods preserve each resource's concrete fluent return type. A scoped compatibility suppression records that intentional metadata generalization; generated release baselines are untouched.

The separate earlier-preview Aspire.Hosting.Radius/withDotnetProgramContainerImage capability ID is retired. SDKs generated against that preview ID must be regenerated.

Validation

Reproduced the missing method with Aspire CLI/SDK 13.6.4 and the integration versions from the issue. Strict TypeScript compilation failed for the modern resource before the fix and passed against the patched generated SDK.

The following commands passed on macOS ARM64 with Podman selected. Quarantined and outerloop tests were excluded. No live Radius deployment was run.

export ASPIRE_CONTAINER_RUNTIME=podman MSBUILDTERMINALLOGGER=false

# Passed: 4 tests.
./dotnet.sh test --project tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests.csproj --no-launch-profile -- --filter-method '*.Generate_RadiusWithContainerImage_*' --filter-method '*.Generate_LegacyAddProject_RetainsDeprecatedBuilderMethod' --filter-method '*.Generate_DotnetProjectOptions_UsesDtoWithoutChangingLegacyOptions' --filter-not-trait 'quarantined=true' --filter-not-trait 'outerloop=true'

# Passed: 4 tests.
./dotnet.sh test --project tests/Aspire.Hosting.RemoteHost.Tests/Aspire.Hosting.RemoteHost.Tests.csproj --no-launch-profile -- --filter-method '*.Invoke_RadiusWithContainerImage_*' --filter-method '*.ScanAssembly_TargetSpecificMethodShadowsGenericExpandedMethodOnlyForThatTarget' --filter-not-trait 'quarantined=true' --filter-not-trait 'outerloop=true'

# Passed: 665 tests.
./dotnet.sh test --project tests/Aspire.Hosting.Radius.Tests/Aspire.Hosting.Radius.Tests.csproj --no-launch-profile -- --filter-not-trait 'quarantined=true' --filter-not-trait 'outerloop=true'

The patched generated SDK also passed the following command from an isolated TypeScript AppHost containing concrete and promise-chain calls for all three resource types:

node node_modules/typescript/bin/tsc --noEmit --module nodenext --target es2022 --strict --types node smoke.mts

Fresh ATS compatibility validation passed with exactly one declared return-type-change suppression and no undeclared breaks. Evaluated test-selection traces reach both new regression consumers from Radius production changes and select the compatibility job for the suppression file.

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

Consolidate Radius container image exports on the shared .NET program overload while preserving the existing capability ID and concrete fluent APIs. Add generated SDK and runtime dispatch regression coverage.

Fixes #21803

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

github-actions Bot commented Nov 5, 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 -- 21830

Or

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

@github-actions github-actions Bot added the area-integrations Issues pertaining to Aspire Integrations packages label Nov 5, 2026
@aspire-repo-bot
aspire-repo-bot Bot requested a balanced review from Copilot November 5, 2026 22:17
@github-actions

github-actions Bot commented Nov 5, 2026

Copy link
Copy Markdown
Contributor

Tests selector

4 / 101 PR test projects · 1 PR job, from 8 changed files.

Selected PR test projects (4 / 101)

Aspire.Cli.EndToEnd.Tests, Aspire.Hosting.CodeGeneration.TypeScript.Tests, Aspire.Hosting.Radius.Tests, Aspire.Hosting.RemoteHost.Tests

Selected PR jobs (1)

typescript-api-compat


How these were chosen — grouped by what changed

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

🔧 src/Aspire.Hosting.Radius/RadiusExtensions.cs (changed source)
→ 1 directly: Aspire.Hosting.Radius.Tests

🔧 src/Aspire.Hosting.Radius/api/Aspire.Hosting.Radius.tscompat.suppression.txt (changed source)
→ 1 directly: Aspire.Hosting.Radius.Tests

🧪 tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests.csproj (changed test)
→ 1 directly: Aspire.Hosting.CodeGeneration.TypeScript.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/AtsTypeScriptCodeGeneratorTests.Generate_RadiusWithContainerImage_PreservesConcreteFluentMethods_includeDotnet=False.verified.ts (changed test)
→ 1 directly: Aspire.Hosting.CodeGeneration.TypeScript.Tests

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

🧪 tests/Aspire.Hosting.RemoteHost.Tests/Aspire.Hosting.RemoteHost.Tests.csproj (changed test)
→ 1 directly: Aspire.Hosting.RemoteHost.Tests

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

Job reasons

Job Triggered by
typescript-api-compat • src/Aspire.Hosting.Radius/api/Aspire.Hosting.Radius.tscompat.suppression.txt
• affected project Aspire.Hosting.Radius

Selection computed for commit ac10a15.

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

No active review issues remain for the restoration of withContainerImage(image) support in generated TypeScript AppHosts.

No open issues 🎉

What changed in this PR

Restores Radius’s withContainerImage(image) method for modern .NET projects in generated TypeScript AppHosts, addressing #21803 without changing the public C# overloads or scanner collision policy.

Changes:

  • Exports the generic overload under the existing withContainerImage capability ID and excludes the legacy overload from discovery.
  • Adds scanning, TypeScript generation, and runtime-dispatch regressions covering legacy projects, file-based apps, and modern .NET projects.
  • Records the intentional metadata return-type generalization in a scoped compatibility suppression. SDKs using the retired preview capability ID must be regenerated.
File Description
tests/​Aspire.Hosting.RemoteHost.Tests/​CapabilityDispatcherTests.cs Tests dispatch, builder identity, and image replacement for all three resource types.
tests/​Aspire.Hosting.RemoteHost.Tests/​Aspire.Hosting.RemoteHost.Tests.csproj Adds Dotnet and Radius references for dispatch tests.
tests/​Aspire.Hosting.CodeGeneration.TypeScript.Tests/​Snapshots/​AtsTypeScriptCodeGeneratorTests.Generate_RadiusWithContainerImage_PreservesConcreteFluentMethods_includeDotnet=True.verified.ts Captures concrete fluent methods and dispatch calls with Dotnet included.
tests/​Aspire.Hosting.CodeGeneration.TypeScript.Tests/​Snapshots/​AtsTypeScriptCodeGeneratorTests.Generate_RadiusWithContainerImage_PreservesConcreteFluentMethods_includeDotnet=False.verified.ts Captures legacy and file-based app methods without Dotnet.
tests/​Aspire.Hosting.CodeGeneration.TypeScript.Tests/​AtsTypeScriptCodeGeneratorTests.cs Verifies real-assembly scanning and generated fluent methods.
tests/​Aspire.Hosting.CodeGeneration.TypeScript.Tests/​Aspire.Hosting.CodeGeneration.TypeScript.Tests.csproj Adds the Radius reference for generation tests.
src/​Aspire.Hosting.Radius/​RadiusExtensions.cs Consolidates exports on the generic overload and clarifies image documentation.
src/​Aspire.Hosting.Radius/​api/​Aspire.Hosting.Radius.tscompat.suppression.txt Documents the intentional capability return-type compatibility exception.

Review effort: Balanced

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

Retiring the preview withDotnetProgramContainerImage capability and generalizing withContainerImage’s return type changes the ATS contract and requires API-owner sign-off.

No open issues 🎉

Review effort: Max

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

area-integrations Issues pertaining to Aspire Integrations packages

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Radius: generic withContainerImage (IDotnetProgramResource) is dropped from the TypeScript surface by method-name collision

2 participants