This repo contains .NET Aspire libraries that enable custom project commands from the Aspire dashboard. There are two NuGet packages plus a sample Aspire app host and sample projects that demonstrate usage.
- Libraries (NuGet):
- Hosting package: Src/Nivot.Aspire.Hosting.ProjectCommander
- Integration package: Src/Nivot.Aspire.ProjectCommander
- Sample Aspire app:
- AppHost: Sample/ProjectCommander.AppHost
- Service defaults: Sample/ProjectCommander.ServiceDefaults
- Sample projects: Sample/DataGenerator, Sample/Consumer, Sample/SpiraLog
- Tests: ProjectCommander.Tests
- Uses .NET SDK 10.0.100 (global.json).
- Solutions: ProjectCommander.sln (primary), Packages.sln (packaging focus).
- Build solution: dotnet build ProjectCommander.sln
- Run tests: dotnet test ProjectCommander.Tests/ProjectCommander.Tests.csproj
- Run sample AppHost with the Aspire CLI: aspire run
- Prefer editing library code under Src/* for product changes; Sample/* is for demos.
- Avoid reformatting unrelated code; keep existing patterns and public APIs stable.
- When adding new public surface area, update README.md if it impacts usage examples.
- Packaging metadata is centralized in Src/Directory.Build.props.
- Hosting extensions and resource wiring live in:
- Src/Nivot.Aspire.Hosting.ProjectCommander/DistributedApplicationBuilderExtensions.cs
- Src/Nivot.Aspire.Hosting.ProjectCommander/ResourceBuilderProjectCommanderExtensions.cs
- Integration client and DI entry points live in:
- Src/Nivot.Aspire.ProjectCommander/ServiceCollectionAspireProjectCommanderExtensions.cs
- Src/Nivot.Aspire.ProjectCommander/AspireProjectCommanderClientWorker.cs
- Keep new tests alongside ProjectCommander.Tests.
- Favor integration-style tests when validating end-to-end command flow.
When creating custom Aspire resources that other resources can WaitFor:
-
Subscribe to
InitializeResourceEvent- Custom resources must opt-in to Aspire's lifecycle by subscribing to this event. Without this, the resource isn't tracked by Aspire's orchestrator. -
Publish
BeforeResourceStartedEventbefore transitioning toRunningstate - This signals to Aspire that the resource is about to start. -
Publish
ResourceReadyEventfor process-less custom resources - Aspire automatically publishesResourceReadyEventfor built-in types (Container, Project, Executable) that have actual processes. For custom resources without a process (likeStartupFormResource), you must manually publish this event to unblockWaitFordependents. -
Resolve services from runtime
ServiceProvider, not build-time builder - When publishing events from command handlers or callbacks that execute at runtime:// WRONG - captured at build time, may not work at runtime await builder.ApplicationBuilder.Eventing.PublishAsync(...); // CORRECT - resolved at runtime var eventing = context.ServiceProvider.GetRequiredService<IDistributedApplicationEventing>(); await eventing.PublishAsync(...);
For resources like startup forms that block until user input:
- Initial state: Custom state (e.g.,
WaitingForConfiguration) - After user completes form:
Running→ publishResourceReadyEvent→Finished
InitializeResourceEvent- First event fired for any resourceBeforeResourceStartedEvent- Just before execution beginsResourceReadyEvent- Unblocks dependents waiting viaWaitFor- Namespace:
Aspire.Hosting.Eventing
- Aspire app model spec: https://github.com/dotnet/aspire/blob/main/docs/specs/appmodel.md