Commit 4517e4a
* Add CLI E2E repro for #15986: dotnet run apphost.cs after aspire init
Demonstrates that 'dotnet run apphost.cs' against the single-file C#
AppHost dropped by interactive 'aspire init' fails because the launch
profile env vars (ASPNETCORE_URLS, ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL,
ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL) are missing — aspire init does not
write apphost.run.json and the .NET file-based runner only honours that
file (not aspire.config.json) for launch profiles.
This commit intentionally adds a failing test; the fix follows in a
subsequent commit on the same PR.
* Fix #15986: emit apphost.run.json from aspire init single-file skeleton
After 'aspire init' drops the C# single-file AppHost ('apphost.cs' +
'aspire.config.json' + 'NuGet.config'), running 'dotnet run apphost.cs'
crashed at startup because no launch profile was applied:
Failed to configure dashboard resource because ASPNETCORE_URLS
environment variable was not set.
Failed to configure dashboard resource because
ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL and
ASPIRE_DASHBOARD_OTLP_HTTP_ENDPOINT_URL are not set.
The dashboard / OTLP / resource service env vars normally come from a
launch profile. When the AppHost is launched via 'aspire run' the CLI
injects them from 'aspire.config.json'. When launched via the .NET
file-based runner ('dotnet run apphost.cs') only '<file>.run.json'
(here 'apphost.run.json') is honoured, and the init flow was not
producing it.
Fix: in InitCommand.DropCSharpSingleFileSkeletonAsync, generate the
profile ports once and pass them into both the existing
'aspire.config.json' writer and a new 'apphost.run.json' writer so the
two files agree on the dashboard URLs. The 'apphost.run.json' shape
mirrors the existing aspire-apphost-singlefile MSBuild template
(commandName=Project, dotnetRunMessages=true, launchBrowser=true,
ASPNETCORE_ENVIRONMENT/DOTNET_ENVIRONMENT=Development, dashboard /
OTLP / resource service URLs).
The aspire-apphost-singlefile MSBuild template is unaffected since it
already ships 'apphost.run.json' alongside its other artifacts. No
other call site of DropAspireConfig is changed (the new ports parameter
is optional and defaults to the previous self-generation behaviour).
Adds InitCommand_SingleFileSkeleton_CreatesAppHostRunJsonWithDashboardEnvVars
unit test and updates the SingleFileAppHostInitDotnetRunTests E2E
repro added in the previous commit.
Fixes #15986
* Add CLI E2E test for #15986: aspire init then dotnet run apphost.cs
Drives the user-facing flow that #15986 broke:
1. `aspire init` (interactive, default C# selection).
2. Inspect the bind-mounted workspace from the host: assert
`apphost.cs`, `aspire.config.json`, and `apphost.run.json` all
exist, and that `apphost.run.json`'s `https` profile carries the
dashboard / OTLP / resource-service env vars (full schema is covered by
`InitCommand_SingleFileSkeleton_CreatesAppHostRunJsonWithDashboardEnvVars`).
3. `dotnet run apphost.cs` and wait for
`Distributed application started.`.
4. Ctrl+C and exit cleanly.
Before the fix, `apphost.run.json` was never written, the precondition
in step 2 fails fast with an explicit pointer to #15986, and step 3
would crash at startup with the dashboard `OptionsValidationException`
about missing `ASPNETCORE_URLS` / `ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL`
(verified on this branch — the test-only commit pushed earlier failed in
CI with exactly that error before the fix landed in this PR).
* Trigger CI revalidation (whitespace only)
* Address PR feedback: shared JSON options + ports always agree
James review feedback on #16812:
1. Use shared JsonSourceGenerationContext.RelaxedEscaping (which already has WriteIndented = true and UnsafeRelaxedJsonEscaping) instead of inline 'new JsonSerializerOptions { WriteIndented = true }' at both ToJsonString call sites in InitCommand.
2. Make divergence between aspire.config.json and apphost.run.json impossible by construction. DropAspireConfig now returns the effective ports (newly generated, or read back from a pre-existing profiles section), and DropCSharpSingleFileSkeletonAsync threads those into DropAppHostRunJson — so even if aspire.config.json was hand-edited or pre-existed, both files always describe the same dashboard / OTLP / resource service endpoints.
Added unit test InitCommand_SingleFileSkeleton_AppHostRunJsonAdoptsPortsFromExistingAspireConfig that pre-seeds aspire.config.json with profiles and asserts apphost.run.json adopts those exact ports.
Also dropped the E2E 'Distributed application started.' wait timeout from 7 minutes to 1 minute — even a cold dotnet build of the bare single-file AppHost completes well inside that budget; if it's not started by then, fail fast.
* Strengthen inline comments at JSON literals (PR #16812 review nits)
James left two nit comments asking for short explanatory comments at the JSON literal blocks. Beef up the comment at the apphost.run.json literal in DropAppHostRunJson explaining what shape it mirrors and why; the existing comment in DropAspireConfig now also calls out that each profile carries the dashboard URL plus the OTLP / resource-service env vars consumed by DashboardOptionsValidator at AppHost startup.
* Address PR feedback: preserve user profiles + use KnownConfigNames
Two more JamesNK review comments on PR #16812:
1. Behavioural regression (line 481): the previous patch overwrote any pre-existing 'profiles' section in aspire.config.json whenever TryReadAppHostProfilePorts couldn't parse all six expected ports (e.g. user-customised config, https-only setup, missing one of the env vars). The original implementation preserved existing profiles unconditionally — this is restoring that safety. New behaviour:
- profiles is null -> write fresh, return those ports
- profiles parses cleanly -> adopt those ports, return them (existing behaviour)
- profiles exists but doesn't match the expected shape -> PRESERVE the user's profiles untouched, generate fresh ports just for apphost.run.json (accepted edge-case divergence — better than silent data loss)
Added InitCommand_SingleFileSkeleton_PreservesUnparseableExistingProfiles to lock the preservation behaviour in.
2. Use KnownConfigNames constants (line 546): replaced literal 'ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL', 'ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL', 'ASPIRE_ALLOW_UNSECURED_TRANSPORT' strings throughout InitCommand.cs (in DropAspireConfig, DropAppHostRunJson, and TryReadAppHostProfilePorts) with KnownConfigNames.DashboardOtlpGrpcEndpointUrl / .ResourceServiceEndpointUrl / .AllowUnsecuredTransport. Test fixtures keep literal strings since they document the on-disk JSON shape from the user's perspective.
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent c8ddbaf commit 4517e4a
3 files changed
Lines changed: 475 additions & 20 deletions
File tree
- src/Aspire.Cli/Commands
- tests
- Aspire.Cli.EndToEnd.Tests
- Aspire.Cli.Tests/Commands
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
18 | 18 | | |
19 | 19 | | |
20 | 20 | | |
| 21 | + | |
21 | 22 | | |
22 | 23 | | |
23 | 24 | | |
| |||
279 | 280 | | |
280 | 281 | | |
281 | 282 | | |
282 | | - | |
283 | | - | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
| 286 | + | |
| 287 | + | |
| 288 | + | |
| 289 | + | |
| 290 | + | |
| 291 | + | |
| 292 | + | |
| 293 | + | |
| 294 | + | |
| 295 | + | |
| 296 | + | |
| 297 | + | |
| 298 | + | |
| 299 | + | |
| 300 | + | |
| 301 | + | |
| 302 | + | |
| 303 | + | |
| 304 | + | |
284 | 305 | | |
285 | | - | |
| 306 | + | |
286 | 307 | | |
287 | 308 | | |
288 | 309 | | |
| |||
402 | 423 | | |
403 | 424 | | |
404 | 425 | | |
405 | | - | |
| 426 | + | |
406 | 427 | | |
407 | 428 | | |
408 | 429 | | |
| |||
426 | 447 | | |
427 | 448 | | |
428 | 449 | | |
429 | | - | |
| 450 | + | |
430 | 451 | | |
431 | 452 | | |
432 | 453 | | |
| |||
451 | 472 | | |
452 | 473 | | |
453 | 474 | | |
454 | | - | |
455 | | - | |
456 | | - | |
457 | | - | |
| 475 | + | |
| 476 | + | |
| 477 | + | |
| 478 | + | |
| 479 | + | |
| 480 | + | |
| 481 | + | |
| 482 | + | |
| 483 | + | |
| 484 | + | |
| 485 | + | |
| 486 | + | |
| 487 | + | |
| 488 | + | |
| 489 | + | |
| 490 | + | |
| 491 | + | |
| 492 | + | |
| 493 | + | |
| 494 | + | |
| 495 | + | |
| 496 | + | |
| 497 | + | |
| 498 | + | |
458 | 499 | | |
459 | | - | |
| 500 | + | |
| 501 | + | |
| 502 | + | |
460 | 503 | | |
| 504 | + | |
| 505 | + | |
| 506 | + | |
461 | 507 | | |
462 | 508 | | |
463 | 509 | | |
464 | 510 | | |
465 | | - | |
| 511 | + | |
466 | 512 | | |
467 | 513 | | |
468 | | - | |
469 | | - | |
| 514 | + | |
| 515 | + | |
470 | 516 | | |
471 | 517 | | |
472 | 518 | | |
473 | 519 | | |
474 | | - | |
| 520 | + | |
475 | 521 | | |
476 | 522 | | |
477 | | - | |
478 | | - | |
479 | | - | |
| 523 | + | |
| 524 | + | |
| 525 | + | |
480 | 526 | | |
481 | 527 | | |
482 | 528 | | |
483 | 529 | | |
484 | 530 | | |
485 | | - | |
486 | | - | |
| 531 | + | |
487 | 532 | | |
488 | 533 | | |
489 | | - | |
| 534 | + | |
| 535 | + | |
| 536 | + | |
| 537 | + | |
| 538 | + | |
| 539 | + | |
| 540 | + | |
| 541 | + | |
| 542 | + | |
| 543 | + | |
| 544 | + | |
| 545 | + | |
| 546 | + | |
| 547 | + | |
| 548 | + | |
| 549 | + | |
| 550 | + | |
| 551 | + | |
| 552 | + | |
| 553 | + | |
| 554 | + | |
| 555 | + | |
| 556 | + | |
| 557 | + | |
| 558 | + | |
| 559 | + | |
| 560 | + | |
| 561 | + | |
| 562 | + | |
| 563 | + | |
| 564 | + | |
| 565 | + | |
| 566 | + | |
| 567 | + | |
| 568 | + | |
| 569 | + | |
| 570 | + | |
| 571 | + | |
| 572 | + | |
| 573 | + | |
| 574 | + | |
| 575 | + | |
| 576 | + | |
| 577 | + | |
| 578 | + | |
| 579 | + | |
| 580 | + | |
| 581 | + | |
| 582 | + | |
| 583 | + | |
| 584 | + | |
| 585 | + | |
| 586 | + | |
| 587 | + | |
| 588 | + | |
| 589 | + | |
| 590 | + | |
| 591 | + | |
| 592 | + | |
| 593 | + | |
| 594 | + | |
| 595 | + | |
| 596 | + | |
| 597 | + | |
| 598 | + | |
| 599 | + | |
| 600 | + | |
| 601 | + | |
| 602 | + | |
| 603 | + | |
| 604 | + | |
| 605 | + | |
| 606 | + | |
| 607 | + | |
| 608 | + | |
| 609 | + | |
| 610 | + | |
| 611 | + | |
| 612 | + | |
| 613 | + | |
| 614 | + | |
| 615 | + | |
| 616 | + | |
| 617 | + | |
| 618 | + | |
| 619 | + | |
| 620 | + | |
| 621 | + | |
| 622 | + | |
| 623 | + | |
| 624 | + | |
| 625 | + | |
| 626 | + | |
| 627 | + | |
| 628 | + | |
| 629 | + | |
| 630 | + | |
| 631 | + | |
| 632 | + | |
| 633 | + | |
| 634 | + | |
| 635 | + | |
| 636 | + | |
| 637 | + | |
| 638 | + | |
| 639 | + | |
| 640 | + | |
| 641 | + | |
| 642 | + | |
| 643 | + | |
| 644 | + | |
| 645 | + | |
| 646 | + | |
| 647 | + | |
| 648 | + | |
| 649 | + | |
| 650 | + | |
| 651 | + | |
| 652 | + | |
| 653 | + | |
| 654 | + | |
| 655 | + | |
| 656 | + | |
| 657 | + | |
| 658 | + | |
| 659 | + | |
| 660 | + | |
| 661 | + | |
490 | 662 | | |
491 | 663 | | |
492 | 664 | | |
0 commit comments