All notable changes to Aspire Project Commander will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
Projects can now define their own commands using a projectcommander.json manifest file placed in the project root directory. This enables projects to be self-describing and portable, without requiring command definitions in the AppHost.
New extension method:
WithProjectManifest<T>()- Reads commands and startup forms from the project'sprojectcommander.jsonfile; returnsIResourceBuilder<T>for chaining
Manifest features:
- Define commands with name, display name, description, and icon
- Specify interactive inputs for commands (Text, SecretText, Choice, Boolean, Number)
- Define startup forms that must be completed before the project starts
Startup forms are now represented as first-class Aspire resources. This enables using Aspire's native WaitFor semantics to block projects until configuration is complete.
New types:
StartupFormResource- Custom Aspire resource representing a startup formStartupFormResourceAnnotation- Links a project to its startup form resource
New extension method:
WithStartupFormBehavior()- Configures the startup form resource with the "Configure" command
How it works:
- Define a
startupFormsection in yourprojectcommander.json - Call
WithProjectManifest()— the startup form resource is automatically created, wired up, and the project is configured to wait for it - The form resource appears in the dashboard with state
WaitingForConfiguration - When the user submits the form, the resource transitions to
Runningand the project starts
Example:
builder.AddProject<Projects.DataGenerator>("datagenerator")
.WithReference(commander)
.WaitFor(commander)
.WithProjectManifest();Client-side:
WaitForStartupFormAsync()still works but returns immediately with cached data since Aspire handles blockingIsStartupFormRequired/IsStartupFormCompleted- Query form stateStartupFormReceivedevent - Fires when form data is received
You can now use both WithProjectManifest() and WithProjectCommands() together. Commands from both sources are merged, with code-based commands taking precedence for duplicate names.
| File | Purpose |
|---|---|
ProjectCommandManifest.cs |
Manifest types for deserializing projectcommander.json |
ManifestReader.cs |
JSON parser and InputDefinition to InteractionInput converter |
StartupFormResource.cs |
Custom Aspire resource for startup forms |
StartupFormResourceAnnotation.cs |
Links project to its startup form resource |
| File | Reason |
|---|---|
StartupFormAnnotation.cs |
Replaced by StartupFormResource and StartupFormResourceAnnotation |
| File | Changes |
|---|---|
ResourceBuilderProjectCommanderExtensions.cs |
WithProjectManifest() automatically wires up the startup form resource |
DistributedApplicationBuilderExtensions.cs |
Added WithStartupFormBehavior() extension |
ProjectCommanderHub.cs |
Uses StartupFormResourceAnnotation, sends cached form data on connect |
IAspireProjectCommanderClient.cs |
Startup form interface members |
AspireProjectCommanderClientWorker.cs |
Handles new ReceiveStartupForm message format |
{
"version": "1.0",
"startupForm": {
"title": "Configure Data Generator",
"inputs": [
{ "name": "delay", "label": "Delay (seconds)", "inputType": "Number", "required": true }
]
},
"commands": [
{ "name": "slow", "displayName": "Go Slow" },
{ "name": "fast", "displayName": "Go Fast" }
]
}From code-based commands to manifest-based:
Before:
builder.AddProject<Projects.DataGenerator>("datagenerator")
.WithReference(commander)
.WithProjectCommands(
new("slow", "Go Slow"),
new("fast", "Go Fast"));After:
- Create
projectcommander.jsonin your project root - Update AppHost:
builder.AddProject<Projects.DataGenerator>("datagenerator")
.WithReference(commander)
.WithProjectManifest();Adding startup form support to existing projects:
- Add
startupFormsection to your manifest - Call
await commander.WaitForStartupFormAsync(stoppingToken)before your main work - Use the returned dictionary to configure your service
- Initial release with code-based command definitions
- Remote resource log viewing via SpiraLog
- SignalR-based communication between AppHost and projects