microsoft / microsoft/aspire

Staging TypeScript AppHost integration restore adds DARC feed without package source mappings

Open
#17,629 0 comments 0 reactions 0 assignees View on GitHub
area-integrations
Dominant language
C#
Stars
6.3k
Forks
991
Avg merge
2d 15h
Merged PRs (30d)
196

Description

# Staging TypeScript AppHost integration restore adds the DARC feed without matching package source mappings

## Context

While validating TypeScript AppHost samples in `CommunityToolkit/Aspire` with a locally installed Aspire CLI build:

```text
aspire --version
13.4.0+e18fdb8e989c2d97b41fab57a7857e223a4a3379
```

the samples were pinned to:

```json
"sdk": {
"version": "13.4.0-preview.1.26275.15"
}
```

Those preview packages restore from the repo-configured `dotnet9` feed. When trying to align the TypeScript AppHost SDK/package pins to `13.4.0`, restore failed for packages such as `Aspire.Hosting.SqlServer` even though the package exists on the CLI-resolved staging/DARC feed.

Example failure:

```text
error NU1103: Unable to find a stable package Aspire.Hosting.SqlServer with version (>= 13.4.0)
- Found 2828 version(s) in dotnet9 [ Nearest version: 13.5.0-preview.1.26277.12 ]
- Versions from https://pkgs.dev.azure.com/dnceng/public/_packaging/darc-pub-microsoft-aspire-e18fdb8e/nuget/v3/index.json were not considered
- Versions from nuget were not considered
```

The DARC feed does contain the stable package:

```text
https://pkgs.dev.azure.com/dnceng/public/_packaging/darc-pub-microsoft-aspire-e18fdb8e/nuget/v3/index.json
Aspire.Hosting.SqlServer: 13.4.0
Aspire.Hosting: 13.4.0
Aspire.AppHost.Sdk: 13.4.0
Aspire.Hosting.AppHost: 13.4.0
```

The repo `NuGet.config` contains package source mappings that route `Aspire.*` packages to `dotnet9`:

```xml

```

## Problem

For TypeScript AppHosts using the prebuilt/bundled AppHost server path, the generated integration restore project adds channel feeds through `RestoreAdditionalProjectSources`, but it does not add corresponding package source mappings.

Example generated project:

```xml

https://api.nuget.org/v3/index.json;
https://pkgs.dev.azure.com/dnceng/public/_packaging/darc-pub-microsoft-aspire-e18fdb8e/nuget/v3/index.json;
https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet9/nuget/v3/index.json

```

That makes the DARC feed visible as a restore source, but NuGet still applies the ambient package source mapping from the repo/user config. Because `Aspire.*` is mapped only to `dotnet9`, NuGet refuses to consider the DARC feed for `Aspire.Hosting.SqlServer` 13.4.0.

## Relevant Aspire CLI code path

The DARC feed appears to come from the staging channel synthesized by:

```text
src/Aspire.Cli/Packaging/PackagingService.cs
PackagingService.GetChannelsAsync()
PackagingService.CreateStagingChannel()
PackagingService.GetStagingFeedUrl()
```

`GetStagingFeedUrl()` derives the DARC feed from the CLI assembly informational version commit hash:

```text
https://pkgs.dev.azure.com/dnceng/public/_packaging/darc-pub-microsoft-aspire-{commitHash}/nuget/v3/index.json
```

The feed then gets added to the generated restore project through:

```text
src/Aspire.Cli/Projects/PrebuiltAppHostServer.cs
BuildIntegrationClosureManifestAsync()
GetNuGetSourcesAsync()
GenerateIntegrationProjectFile()
```

`GenerateIntegrationProjectFile()` emits `RestoreAdditionalProjectSources`, which does not carry package source mapping information.

There is existing code that can create a temporary NuGet.config with mappings (`TryCreateTemporaryNuGetConfigAsync()`), but the project-reference integration restore path only uses it when a package source override is present:

```csharp
using var temporaryNuGetConfig = !string.IsNullOrWhiteSpace(packageSourceOverride)
? await TryCreateTemporaryNuGetConfigAsync(...)
: null;
```

With no override, the path falls back to `RestoreAdditionalProjectSources`, so channel-specific mappings are lost.

## Resulting issue

During local development / staging validation, a TypeScript AppHost that needs project-reference integration restore can fail to restore stable Aspire packages from the CLI-resolved DARC feed if the user's/repo's NuGet.config contains package source mappings for `Aspire.*`.

This can make the failure look like the package is missing:

```text
Unable to find a stable package Aspire.Hosting.SqlServer with version (>= 13.4.0)
```

but the package is actually present; it is just excluded by package source mapping.

## Why the AppHost type matters

This appears tied to the AppHost server implementation used for local development / TypeScript AppHosts.

The generated restore project under:

```text
.aspire/integrations/apphosts//integration-restore/IntegrationRestore.csproj
```

is produced by the prebuilt/bundled AppHost server path (`PrebuiltAppHostServer`). That path resolves CLI package channels and writes `RestoreAdditionalProjectSources` into the synthetic integration restore project. Because the restore happens in a generated project outside the normal app project, the way sources/mappings are injected there determines whether staging/DARC packages can be restored.

This is different from a normal C# AppHost project restore, where the project and its NuGet configuration are the primary restore inputs.

## Scope

This is expected to affect staging/local validation scenarios where the CLI resolves a SHA-specific DARC feed for stable-shaped packages before they are available from the normal stable release sources. It should not affect a final release bundle once the stable packages are available through the release channel/source configuration that the bundle is intended to use.

In other words, the issue is not that the final `13.4.0` packages are missing from the staging DARC feed; they are present. The problem is that, for this local/staging AppHost restore path, the generated restore project adds that feed as an additional source without making it eligible for `Aspire.*` under package source mapping.

## Expected behavior

When Aspire CLI resolves an explicit channel feed for integration restore, especially staging/DARC feeds, the generated restore should also preserve the package source mappings required for that channel. For example, the DARC source should be eligible for `Aspire*` packages when it is the resolved staging channel source.

Possible fixes:

1. Use a temporary NuGet.config with channel mappings for the project-reference integration restore path, not only when `packageSourceOverride` is set.
2. Or otherwise extend the generated restore project/source setup so `Aspire*` packages are mapped to the resolved DARC feed.
3. Ensure any ambient repo/user `packageSourceMapping` cannot exclude the channel feed that the CLI explicitly resolved for the AppHost SDK/integration restore.

## Repro outline

1. Use a TypeScript AppHost with an Aspire package reference, e.g. `Aspire.Hosting.SqlServer`.
2. Use an Aspire CLI build whose staging channel resolves to a DARC feed containing stable `13.4.0` packages.
3. Have an ambient `NuGet.config` with package source mapping that maps `Aspire.*` to `dotnet9`.
4. Pin the TypeScript AppHost SDK/package to `13.4.0`.
5. Run:

```bash
aspire restore --apphost apphost.mts
```

Expected: restore uses the CLI-resolved DARC feed for `Aspire.*`.

Actual: restore sees the DARC feed in `RestoreAdditionalProjectSources`, but NuGet source mapping excludes it for `Aspire.*`, resulting in `NU1103`.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.