microsoft / microsoft/aspire

Make `WithInitialState()` callable multiple times

Open
#13,633 1 comment 0 reactions 0 assignees View on GitHub
area-app-model
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

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.