Add optional parameters and programmatic value setting#18108
Conversation
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 18108Or
iex "& { $(irm https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 18108" |
663b2d2 to
564a208
Compare
There was a problem hiding this comment.
Pull request overview
This PR adds first-class support for optional parameter resources and programmatic parameter value management in Aspire. It introduces a Required property on ParameterResource (defaulting to true), fluent builder extensions (WithOptional(), WithRequired()), and a suite of value-management methods (TrySetValue, TrySetException, SetValueAsync, SetExceptionAsync, TryGetCurrentValue). The ParameterProcessor is refactored to use an observer pattern via ValueChanged events instead of directly manipulating internal TaskCompletionSource state, enabling dashboard state synchronization when values are set programmatically. ATS code generation is updated to propagate nullability metadata for parameters and return types.
Changes:
- New
ParameterResourcepublic API for optional parameters and programmatic value management, with an internal event-based observer pattern consumed byParameterProcessorfor dashboard state synchronization. ParameterProcessorrefactored to use thread-safe collections with locks, observer-based state updates, and a newSetValueAsyncmethod for non-interactive value setting.- ATS capability scanner updated to detect and propagate C# nullability annotations for method parameters and return types, reflected in TypeScript codegen snapshots.
Show a summary per file
| File | Description |
|---|---|
src/Aspire.Hosting/ApplicationModel/ParameterResource.cs |
Core changes: Required property, TryGetCurrentValue, TrySetValue, TrySetException, SetValueAsync, SetExceptionAsync, ValueChanged event, ParameterResourceValueChangedEventArgs |
src/Aspire.Hosting/Orchestrator/ParameterProcessor.cs |
Refactored to observer pattern: ObserveParameterValueChanges, thread-safe unresolved parameters, SetValueAsync for non-interactive value setting, SetValueCoreAsync |
src/Aspire.Hosting/ParameterResourceBuilderExtensions.cs |
New WithOptional() and WithRequired(bool) fluent extension methods |
src/Aspire.Hosting/Publishing/ManifestPublishingContext.cs |
Emits "required": false in manifest for optional parameters |
src/Aspire.Hosting.RemoteHost/AtsCapabilityScanner.cs |
Adds NullabilityInfoContext-based nullability detection for parameters and return types, GetEffectiveNullability to unwrap Task<T?>/ValueTask<T?> |
playground/TypeScriptAppHost/apphost.mts |
Playground example using addParameter().withOptional() and tryGetCurrentValue/setValueAsync |
tests/Aspire.Hosting.Tests/AddParameterTests.cs |
Tests for optional parameters, TrySetValue, SetValueAsync, TrySetException, SetExceptionAsync, manifest output |
tests/Aspire.Hosting.Tests/Orchestrator/ParameterProcessorTests.cs |
Tests for processor integration: optional init, programmatic set, dashboard state sync, delete optional |
tests/Aspire.Hosting.Tests/ExecutionConfigurationGathererTests.cs |
Test verifying unset optional parameter env vars are omitted |
tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests/AtsTypeScriptCodeGeneratorTests.cs |
Tests for ATS scanner detecting nullable parameter/return types |
tests/.../Snapshots/WithOptionalStringCapability.verified.txt |
Updated snapshot with IsNullable: true |
tests/.../Snapshots/AddTestRedisCapability.verified.txt |
Updated snapshot with IsNullable: true |
tests/.../Snapshots/WithDataVolumeOptionsMerged.verified.ts |
TypeScript type updated to string | null |
tests/.../Snapshots/AtsGeneratedAspire.verified.ts |
Full generated TypeScript updated with | null for nullable optional params |
Copilot's findings
- Files reviewed: 14/15 changed files
- Comments generated: 1
Make Aspire parameters first-class for both optionality and runtime value management, and surface the new capabilities to polyglot hosts. Optional parameters: - WithOptional() marks a parameter resource as optional so a missing value no longer prompts or fails resolution; WithRequired() restores the default required behavior. Custom-input parameters honor the Required flag. Programmatic value management: - ParameterResource.SetValueAsync / TryGetCurrentValue let code set and read a parameter's value at runtime. - ParameterProcessor.SetValueAsync is the persistence-aware path: with saveToUserSecrets it writes the value back to user secrets, and setting a value notifies observers so the dashboard reflects the change live. Polyglot exposure: - The new methods are exported via ATS ([AspireExport]) so TypeScript, Java, Python, Go, and Rust app hosts get them. The generated bindings are additive only - no changes to the existing generated surface. Reference-type nullability is intentionally not propagated into the model, preserving the established convention (for example getConnectionString() stays non-null). Publish vs run: - ManifestPublishingContext handles optional parameters when publishing. Includes unit tests for AddParameter optionality, ParameterProcessor value management and notification, execution configuration gathering, and the ATS scanner capability for the new parameter methods. Related: #17710 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
50c76c3 to
3d326cb
Compare
|
❓ CLI E2E Tests unknown — 114 passed, 0 failed, 2 unknown (commit View all recordings
📹 Recordings uploaded automatically from CI run #27356599605 |
Description
Parameters currently do not have a complete first-class model for two related scenarios: optional parameters that can intentionally have no value, and programmatic parameter values that can be set by AppHost code instead of only through configuration, prompts, or generated defaults. This change adds both pieces so run, publish, dashboard, C# AppHost, and TypeScript AppHost flows share the same parameter value contract.
Users can now mark parameter resources optional with
WithOptional()/WithRequired(...), allowing unset optional parameters to resolve tonullwithout prompting or blocking publish. Users can also inspect and set parameter values programmatically withTryGetCurrentValue(...)andSetValueAsync(...); observed parameter updates synchronize dashboard state, resolve missing-value prompts, and preserve required-parameter validation when a required parameter is cleared.The implementation centralizes value state on
ParameterResourceand refactorsParameterProcessorto consume that public/resource-level contract instead of manipulating internal completion state directly. ATS and TypeScript generation expose the value-management APIs, including nullable value metadata forsetValueAsyncandtryGetCurrentValue.User-facing usage
C# AppHost:
TypeScript AppHost:
The TypeScript playground now includes this pattern and passes the parameter to the API as
MESSAGE_PREFIX.Validation
./build.sh --build /p:SkipNativeBuild=true /p:RepositoryCommit=$(git rev-parse HEAD)dotnet test --project tests/Aspire.Hosting.Tests/Aspire.Hosting.Tests.csproj --no-launch-profile -- --filter-class "*.AddParameterTests" --filter-class "*.ParameterProcessorTests" --filter-not-trait "quarantined=true" --filter-not-trait "outerloop=true"git diff --checkFixes #17710
Checklist
<remarks />and<code />elements on your triple slash comments?