Aspire localhost TLD (*.dev.localhost) URLs break Codespaces port forwarding
- Dominant language
- C#
- Stars
- 6.3k
- Forks
- 991
- Avg merge
- 2d 15h
- Merged PRs (30d)
- 196
Description
## Summary
When using Aspire's `--localhost-tld` option (which creates URLs like `https://myapp.dev.localhost:17000`), the terminal URL detection in GitHub Codespaces fails to automatically forward ports. Users must manually forward ports through the Codespaces UI.
## Reproduction Steps
1. Create a new Aspire project in a GitHub Codespace with the localhost TLD option enabled:
```bash
aspire new --localhost-tld
```
2. Run the project:
```bash
dotnet run --project MyApp.AppHost
```
3. Observe the terminal output displays URLs like:
```
Now listening on: https://myapp-apphost.dev.localhost:17000
Login to the dashboard at https://myapp-apphost.dev.localhost:17000/login?t=...
```
4. **Expected:** Codespaces should auto-detect the localhost URL and offer to forward the port
5. **Actual:** No port forwarding is triggered; the URL is not clickable/accessible
## Root Cause
The `CodespacesResourceUrlRewriterService` only rewrites URLs when the host is **exactly** `"localhost"`:
```csharp
// src/Aspire.Hosting/Devcontainers/Codespaces/CodespacesResourceUrlRewriterService.cs:36
if (!originalUrlSnapshot.IsInternal && (uri.Scheme == "http" || uri.Scheme == "https") && uri.Host == "localhost")
```
When `--localhost-tld` is enabled, the dashboard URL becomes `https://myproject-apphost.dev.localhost:17000`. This **does not match** the `uri.Host == "localhost"` condition because `uri.Host` is `myproject-apphost.dev.localhost`, not `localhost`.
As a result:
1. The Codespaces URL rewriter skips these URLs
2. The terminal outputs `*.dev.localhost` URLs unchanged
3. Codespaces' terminal URL detection doesn't recognize these as localhost URLs
4. Port forwarding is not triggered automatically
## Proposed Fix
Use the existing `EndpointHostHelpers.IsLocalhostOrLocalhostTld()` helper method which already handles all localhost variants:
```csharp
// Before (line 36):
if (!originalUrlSnapshot.IsInternal && (uri.Scheme == "http" || uri.Scheme == "https") && uri.Host == "localhost")
// After:
if (!originalUrlSnapshot.IsInternal && (uri.Scheme == "http" || uri.Scheme == "https")
&& EndpointHostHelpers.IsLocalhostOrLocalhostTld(uri))
```
This is a minimal, single-line change that leverages existing infrastructure.
## Affected Files
- `src/Aspire.Hosting/Devcontainers/Codespaces/CodespacesResourceUrlRewriterService.cs` (primary)
- Possibly `src/Aspire.Hosting/Devcontainers/Codespaces/CodespacesUrlRewriter.cs` if called from other paths
## Alternative Considerations
1. **Auto-disable `--localhost-tld` in Codespaces**: Detect the environment and warn or fallback to regular localhost URLs
2. **Documentation**: Document that `--localhost-tld` doesn't work optimally in Codespaces (not ideal UX)
3. **Hybrid display**: Show both Codespaces URL and original `.dev.localhost` URL in terminal
## Environment
- Aspire version: main branch / .NET 10
- Environment: GitHub Codespaces
- Feature: `--localhost-tld` template option
## Additional Context
- The `.localhost` TLD is an IETF reserved TLD (RFC 2606) that always resolves to `127.0.0.1`
- Browsers and OS handle `.localhost` specially, but port forwarding tools (including Codespaces) often only look for exact `localhost` matches
- The helper method `EndpointHostHelpers.IsLocalhostOrLocalhostTld()` already exists in the codebase for this exact purpose
Contributor guide
Assessment
This issue has not been assessed yet.