Make ValueProviderContext.ExecutionContext non-nullable
- Dominant language
- C#
- Stars
- 6.3k
- Forks
- 991
- Avg merge
- 2d 15h
- Merged PRs (30d)
- 196
Description
### Background
`DistributedApplicationExecutionContext` is registered as a singleton in DI from the very start of the AppHost lifecycle (`DistributedApplicationBuilder.cs:588`), so it is always available wherever you have access to the AppHost's `IServiceProvider`. Despite this, a handful of public APIs model it as nullable, which forces every consumer to defensively write `ctx.ExecutionContext?.IsPublishMode == true` (or similar) — easy to get wrong, and the "null" arm is unreachable in practice for any non-test caller.
#16700 tightened `ContainerBuildOptionsCallbackContext.ExecutionContext` (experimental API) to non-nullable. This issue tracks doing the same for the rest of the surface.
### Nullable surface remaining
1. **`ValueProviderContext.ExecutionContext`** (`src/Aspire.Hosting/ApplicationModel/IValueProvider.cs`) — public, non-experimental, `init`-only nullable property.
2. **Consumer call sites that use the defensive `?.` pattern** (or fall through to `null` because nobody plumbed a context in):
- `src/Aspire.Hosting/ApplicationModel/HostUrl.cs:45,108` — `context.ExecutionContext?.IsRunMode == true`
- `src/Aspire.Hosting/ApplicationModel/ContainerImageReference.cs:48` — `context.ExecutionContext?.ServiceProvider is { } serviceProvider`
3. **Construction sites that produce `null` execution contexts**:
- `src/Aspire.Hosting/ApplicationModel/ContainerImageReference.cs:41` — `new ValueProviderContext()` (no args) from the parameterless `IValueProvider.GetValueAsync(CancellationToken)` overload.
- The default interface implementation `IValueProvider.GetValueAsync(ValueProviderContext, CancellationToken)` in `IValueProvider.cs:42–43` forwards to the parameterless overload, throwing away any caller-provided context.
### Proposed work
- Mark `ValueProviderContext.ExecutionContext` as `required` and non-nullable.
- Either:
- Update `ContainerImageReference`'s parameterless path to construct a `ValueProviderContext` with an execution context resolved from the resource's service provider; **or**
- Delete the parameterless `IValueProvider.GetValueAsync(CancellationToken)` overload (or at least the default-implementation shortcut that drops the context).
- Drop the `?.` checks in `HostUrl.cs` and `ContainerImageReference.cs`.
- Audit all hosting integrations (in-tree) for `new ValueProviderContext { ... }` sites that don't pass `ExecutionContext` and fix.
### Considerations
- `ValueProviderContext` is a **public, non-experimental** type on `Aspire.Hosting`. Out-of-tree hosting integrations that implement custom `IValueProvider`s and construct their own `ValueProviderContext` instances will need to update. This should be called out in release notes / breaking-change docs.
- Worth deciding at the same time whether the parameterless `IValueProvider.GetValueAsync(CancellationToken)` overload should be deprecated/removed — that's where the original nullability leaked from.
### Context
Spun out of review on #16700.
Contributor guide
Research direction
Start in src/Aspire.Hosting/ApplicationModel/IValueProvider.cs, then inspect the listed HostUrl.cs and ContainerImageReference.cs call sites and in-tree ValueProviderContext construction sites. Decide how the parameterless overload should be handled, make ExecutionContext required and non-nullable, update consumers and integrations, and document the public breaking change in release notes or breaking-change documentation.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp
- Domain
- backend-api-design
- Issue type
- Refactor
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100