Make `WithInitialState()` callable multiple times
- Dominant language
- C#
- Stars
- 6.3k
- Forks
- 991
- Avg merge
- 2d 15h
- Merged PRs (30d)
- 196
Description
## Background and Motivation
For configuring a Resource's initial state, there is the `WithInitialState()` api. However this API doesn't work particularly well if you need to set the initial state across different parts of your resource's initialisation. `IsHidden` is one such example. Or you may be inheriting from another resource type and want to add some custom properties to the resource state but without overwriting whatever the existing resource has done.
You can sort of work around this today by faffing with `ResourceNotificationService.PublishUpdateAsync()` in an early lifecycle event, but it's a bit messy.
## Proposed API
Rather than `WithInitialState()` taking a complete `CustomResourceSnapshot` object, make it a callback which takes the state so far, and gives you an opportunity to update it. Much like whow `ResourceNotificationService.PublishUpdateAsync()` works.
```diff
namespace Aspire.Hosting;
public static class CustomResourceExtensions
{
- public static IResourceBuilder WithInitialState(this IResourceBuilder builder, CustomResourceSnapshot initialSnapshot)
- where TResource : IResource
+ public static IResourceBuilder WithInitialState(this IResourceBuilder builder, Func stateFactory)
+ where TResource : IResource
```
In the short term, the existing method would be obsoleted rather than removed outright. To retain backward compatibility, aspire would still look for the existing `ResourceSnapshotAnnotation` annotation, and if it finds that, use that as the state to pass in to the first callback.
## Usage Examples
Hiding a resource by default
```cs
builder.WithInitialState(x => x with { IsHidden = true });
```
Adding an additional property
```csharp
builder.WithInitialState(x => x with {
Properties = [
..x.Properties,
new("foo", "bar")
]
})
```
## Alternative Designs
An alternative design could be to keep the current `WithInitialState`, but change it to merge the new state into the current state. This would work, but it does have some awkward edge cases to work out particularly around how to merge the Properties array, and a later state could remove a property provided by an earlier call.
## Risks
The only risk I see is when the breaking change when it comes to eventually removing the older `WithInitialState` we initially obsolete.
Contributor guide
Assessment
This issue has not been assessed yet.