You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
aspire add picker displays wrong version for C# AppHosts pinned to a non-default channel (pin ignored, installed version differs from displayed) #17294
For a C# AppHost (*.csproj with <IsAspireHost>true</IsAspireHost>), aspire add and aspire integration list ignore the channel pin in aspire.config.json. The picker fans out to every available channel
(Implicit / Stable / Daily / Staging / hives) and dedupes by package id
with Implicit always winning over any Explicit channel. The result: for
any integration that's available from both the user's ambient nuget.config (Implicit) and the project's pinned channel, the stable
version is displayed in the picker.
On aspire add <integration>, the project's nuget.config (which is
written with the matching channel's packageSource + packageSource Mapping) takes over and dotnet add package resolves the PR /
localhive version at restore time. The displayed version is therefore
different from the version that actually gets installed.
Polyglot AppHosts (TypeScript / Python / Go / Java / Rust) do NOT have
this bug: they honor aspire.config.json#channel and display the
pinned-channel version. So a user can see the asymmetry inside a single
install simply by switching the AppHost language.
Repro
Repro reproduces on the current main daily/dev build as well as on
PR #17105 — see "Reproduces on" below.
Setup a PR-acquired install:
./eng/scripts/get-aspire-cli-pr.sh 17105 \
--install-path /tmp/aspire-issue-val --skip-extension --skip-path
CLI=/tmp/aspire-issue-val/dogfood/pr-17105/bin/aspire
# Two projects with the same channel pin — only the language differs.
mkdir -p /tmp/aspire-issue-val/cs-demo/cs.AppHost /tmp/aspire-issue-val/ts-demo
cat > /tmp/aspire-issue-val/cs-demo/cs.AppHost/cs.AppHost.csproj <<'EOF'<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>net10.0</TargetFramework> <IsAspireHost>true</IsAspireHost> </PropertyGroup></Project>EOF
cat > /tmp/aspire-issue-val/cs-demo/aspire.config.json <<'EOF'{ "channel": "pr-17105" }EOF
cat > /tmp/aspire-issue-val/ts-demo/apphost.ts <<'EOF'// stubEOF
cat > /tmp/aspire-issue-val/ts-demo/aspire.config.json <<'EOF'{ "channel": "pr-17105" }EOF# What version of Redis does each project's picker show?echo"=== C# AppHost ==="$CLI integration list --apphost /tmp/aspire-issue-val/cs-demo/cs.AppHost/cs.AppHost.csproj \
--format json | jq '.[] | select(.package == "Aspire.Hosting.Redis")'echo"=== TypeScript AppHost ==="$CLI integration list --apphost /tmp/aspire-issue-val/ts-demo/apphost.ts \
--format json | jq '.[] | select(.package == "Aspire.Hosting.Redis")'
Expected
Both AppHosts honor aspire.config.json#channel. The picker displays
the same channel-pinned version that dotnet add package will actually
install. A C# AppHost pinned to pr-17105 displays Aspire.Hosting.Redis 13.4.0-pr.17105.<sha>, not a stable version.
Same install, same hive, same channel pin in aspire.config.json —
different version displayed depending only on AppHost language. On aspire add redis, the C# project resolves the PR version at restore
time anyway (via the nuget.config package-source-mapping written
during scaffolding), so the displayed 13.3.4 is a lie about what the
user actually ends up with.
Daily/dev install (13.4.0-preview.1.26269.7, installed via https://aka.ms/aspire/get/install.sh --quality dev): same shape.
With a nonexistent pr-99999 pin in aspire.config.json, C# returns
128 rows (pin completely ignored); polyglot returns 0 rows (pin
honored, filters to nonexistent channel). The asymmetry is intrinsic
to the code path, not the install route.
This short-circuit was written under the assumption that C# projects
express their channel via nuget.config rather than aspire.config.json. But aspire add's picker is a discovery surface,
not a restore mechanism — the user needs to see the version that's
about to be installed. The two concerns ("which source does dotnet add package use?" vs. "which version does the picker display?") were
conflated.
The downstream dedup at SelectPreferredIntegrationPackage
(line 131-137) then prefers Implicit:
So even when the PR hive contributes a higher semver, Implicit's lower
semver wins for any shared id.
Scope
Affects:
aspire add interactive picker
aspire integration list
aspire integration search
MCP list-integrations tool
…all only for C# AppHosts with a non-default aspire.config.json# channel pin. Polyglot AppHosts work correctly.
Does not affect:
Restore-time resolution (the project's nuget.config correctly
routes Aspire* to the hive via packageSourceMapping). The actual
installed package is correct; only the picker's displayed version is
wrong.
Default-channel C# AppHosts (no other channel competes for dedup).
Possible directions
Honor aspire.config.json#channel for C# AppHosts too — read the
pin and use it as the channel filter, same way polyglot does.
Add a per-row channel column to the picker so the user can see that
the displayed version came from default while a pr-17105 row
also exists at a different version.
Reverse the dedup preference so a configured-channel match beats
Implicit when the project is pinned to that channel.
Notes
Related to #17225 (about which channel gets used during scaffolding) and #17292 (about which packages are eligible for the picker after PR #17105
aligned hive-channel filtering with non-hive). This issue is about what
the picker displays for an already-pinned C# project.
Counterpart: #17295 — polyglot AppHosts have the opposite
problem (the pin is honored too strictly and removes all off-channel
integrations from the picker).
What's broken
For a C# AppHost (
*.csprojwith<IsAspireHost>true</IsAspireHost>),aspire addandaspire integration listignore thechannelpin inaspire.config.json. The picker fans out to every available channel(Implicit / Stable / Daily / Staging / hives) and dedupes by package id
with Implicit always winning over any Explicit channel. The result: for
any integration that's available from both the user's ambient
nuget.config(Implicit) and the project's pinned channel, the stableversion is displayed in the picker.
On
aspire add <integration>, the project'snuget.config(which iswritten with the matching channel's
packageSource+packageSource Mapping) takes over anddotnet add packageresolves the PR /localhive version at restore time. The displayed version is therefore
different from the version that actually gets installed.
Polyglot AppHosts (TypeScript / Python / Go / Java / Rust) do NOT have
this bug: they honor
aspire.config.json#channeland display thepinned-channel version. So a user can see the asymmetry inside a single
install simply by switching the AppHost language.
Repro
Repro reproduces on the current
maindaily/dev build as well as onPR #17105 — see "Reproduces on" below.
Setup a PR-acquired install:
./eng/scripts/get-aspire-cli-pr.sh 17105 \ --install-path /tmp/aspire-issue-val --skip-extension --skip-path CLI=/tmp/aspire-issue-val/dogfood/pr-17105/bin/aspire # Two projects with the same channel pin — only the language differs. mkdir -p /tmp/aspire-issue-val/cs-demo/cs.AppHost /tmp/aspire-issue-val/ts-demo cat > /tmp/aspire-issue-val/cs-demo/cs.AppHost/cs.AppHost.csproj <<'EOF' <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>net10.0</TargetFramework> <IsAspireHost>true</IsAspireHost> </PropertyGroup> </Project> EOF cat > /tmp/aspire-issue-val/cs-demo/aspire.config.json <<'EOF' { "channel": "pr-17105" } EOF cat > /tmp/aspire-issue-val/ts-demo/apphost.ts <<'EOF' // stub EOF cat > /tmp/aspire-issue-val/ts-demo/aspire.config.json <<'EOF' { "channel": "pr-17105" } EOF # What version of Redis does each project's picker show? echo "=== C# AppHost ===" $CLI integration list --apphost /tmp/aspire-issue-val/cs-demo/cs.AppHost/cs.AppHost.csproj \ --format json | jq '.[] | select(.package == "Aspire.Hosting.Redis")' echo "=== TypeScript AppHost ===" $CLI integration list --apphost /tmp/aspire-issue-val/ts-demo/apphost.ts \ --format json | jq '.[] | select(.package == "Aspire.Hosting.Redis")'Expected
Both AppHosts honor
aspire.config.json#channel. The picker displaysthe same channel-pinned version that
dotnet add packagewill actuallyinstall. A C# AppHost pinned to
pr-17105displaysAspire.Hosting.Redis 13.4.0-pr.17105.<sha>, not a stable version.Actual
Same install, same hive, same channel pin in
aspire.config.json—different version displayed depending only on AppHost language. On
aspire add redis, the C# project resolves the PR version at restoretime anyway (via the
nuget.configpackage-source-mapping writtenduring scaffolding), so the displayed
13.3.4is a lie about what theuser actually ends up with.
Reproduces on
aspire doctorlists every Aspire CLI install on the machine #17105 install (13.4.0-pr.17105.g93e48e16): C# returns 118 rowsincluding stable Redis; polyglot returns 58 rows including PR Redis.
13.4.0-preview.1.26269.7, installed viahttps://aka.ms/aspire/get/install.sh --quality dev): same shape.With a nonexistent
pr-99999pin inaspire.config.json, C# returns128 rows (pin completely ignored); polyglot returns 0 rows (pin
honored, filters to nonexistent channel). The asymmetry is intrinsic
to the code path, not the install route.
Why
src/Aspire.Cli/Commands/IntegrationPackageSearchService.cs:88-91:This short-circuit was written under the assumption that C# projects
express their channel via
nuget.configrather thanaspire.config.json. Butaspire add's picker is a discovery surface,not a restore mechanism — the user needs to see the version that's
about to be installed. The two concerns ("which source does
dotnet add packageuse?" vs. "which version does the picker display?") wereconflated.
The downstream dedup at
SelectPreferredIntegrationPackage(line 131-137) then prefers Implicit:
So even when the PR hive contributes a higher semver, Implicit's lower
semver wins for any shared id.
Scope
Affects:
aspire addinteractive pickeraspire integration listaspire integration searchlist-integrationstool…all only for C# AppHosts with a non-default
aspire.config.json# channelpin. Polyglot AppHosts work correctly.Does not affect:
nuget.configcorrectlyroutes
Aspire*to the hive viapackageSourceMapping). The actualinstalled package is correct; only the picker's displayed version is
wrong.
Possible directions
aspire.config.json#channelfor C# AppHosts too — read thepin and use it as the channel filter, same way polyglot does.
the displayed version came from
defaultwhile apr-17105rowalso exists at a different version.
Implicit when the project is pinned to that channel.
Notes
Related to #17225 (about which channel gets used during scaffolding) and
#17292 (about which packages are eligible for the picker after PR #17105
aligned hive-channel filtering with non-hive). This issue is about what
the picker displays for an already-pinned C# project.
Counterpart: #17295 — polyglot AppHosts have the opposite
problem (the pin is honored too strictly and removes all off-channel
integrations from the picker).