Update AppHost eventing docs to use typed helper APIs - #1168
Update AppHost eventing docs to use typed helper APIs#1168David Pine (IEvangelist) with Copilot wants to merge 3 commits into
Conversation
Co-authored-by: IEvangelist <7679720+IEvangelist@users.noreply.github.com>
Co-authored-by: IEvangelist <7679720+IEvangelist@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR updates Aspire AppHost eventing documentation and related snippets to prefer the newer typed helper APIs (for example OnBeforeStart, OnInitializeResource, OnConnectionStringAvailable) over lower-level builder.Eventing.Subscribe<T>() patterns, aligning guidance and examples with the current recommended API surface.
Changes:
- Updated release notes snippets to use
On*helper methods instead of legacy subscription APIs. - Refactored the architecture “resource examples” snippet to use
OnConnectionStringAvailableand reuse the same resource builder instance. - Updated the AppHost eventing page to describe helper methods, add API reference links, and include an
OnResourceStoppedmention/example.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| src/frontend/src/content/docs/whats-new/aspire-9-3.mdx | Updates the InitializeResource example to use .OnInitializeResource(...). |
| src/frontend/src/content/docs/whats-new/aspire-13-3.mdx | Updates C# lifecycle event snippet to use OnBeforeStart/OnAfterResourcesCreated. |
| src/frontend/src/content/docs/architecture/resource-examples.mdx | Updates connection-string capture to use .OnConnectionStringAvailable(...) and reuses redisBuilder. |
| src/frontend/src/content/docs/app-host/eventing.mdx | Clarifies helper-method guidance, adds API reference links, and updates resource-stopped example. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| </Tabs> | ||
|
|
||
| The following builder-level extension methods are available for AppHost events: | ||
| The following builder-level helper methods are available for AppHost events: |
| For the full API surface, see the [.NET | ||
| `DistributedApplicationEventingExtensions`](https://learn.microsoft.com/dotnet/api/aspire.hosting.distributedapplicationeventingextensions) | ||
| API reference and the [TypeScript `Aspire.Hosting` API | ||
| reference](/reference/api/typescript/aspire.hosting/). |
| // 6. Add & configure container using the fluent builder pattern | ||
| // Add the RedisResource instance to the application model. | ||
| return builder.AddResource(redis) | ||
| // 6.a Expose the Redis TCP endpoint | ||
| // Map the host port (if provided) to the container's default Redis port (6379). | ||
| // Name the endpoint "tcp" for reference. | ||
| .WithEndpoint( | ||
| port: port, // Optional host port. | ||
| targetPort: 6379, // Default Redis port inside the container. | ||
| name: RedisResource.PrimaryEndpointName) // Use the constant defined in RedisResource. | ||
| // 6.b Specify container image and tag | ||
| // Define the Docker image to use for the Redis container. | ||
| .WithImage(RedisContainerImageTags.Image, RedisContainerImageTags.Tag) | ||
| // 6.c Configure container registry if needed | ||
| // Specify a container registry if the image is not on Docker Hub. | ||
| .WithImageRegistry(RedisContainerImageTags.Registry) | ||
| // 6.d Wire the health check into the resource | ||
| // Associate the previously defined health check with this resource. | ||
| // Aspire uses this for dashboard status and orchestration. | ||
| .WithHealthCheck(healthCheckKey) | ||
| // 6.e Define the container's entrypoint | ||
| // Override the default container entrypoint if necessary. Here, it's set to use shell. | ||
| .WithEntrypoint("/bin/sh") | ||
| // 6.f Pass the password ParameterResource into an environment variable | ||
| // Set environment variables for the container. This uses a callback to access | ||
| // the resource instance (`redis`) and its properties. | ||
| .WithEnvironment(context => | ||
| { | ||
| // If a password parameter exists, expose it as the REDIS_PASSWORD environment variable. | ||
| // The actual value resolution happens later via the ParameterResource. | ||
| if (redis.PasswordParameter is { } pwd) | ||
| { | ||
| context.EnvironmentVariables["REDIS_PASSWORD"] = pwd; | ||
| } | ||
| }) | ||
| // 6.g Build the container arguments lazily, preserving annotations | ||
| // Define the command-line arguments for the container. This also uses a callback | ||
| // to allow dynamic argument construction based on resource state or annotations. | ||
| .WithArgs(context => | ||
| { | ||
| // Start with the basic command to run the Redis server. | ||
| var cmd = new List<string> { "redis-server" }; | ||
|
|
||
| // If a password parameter is set, add the necessary Redis CLI arguments. | ||
| // Note: It uses the environment variable name set earlier ($REDIS_PASSWORD). | ||
| if (redis.PasswordParameter is not null) | ||
| { | ||
| cmd.Add("--requirepass"); | ||
| cmd.Add("$REDIS_PASSWORD"); // Reference the environment variable. | ||
| } | ||
|
|
||
| // Check if a PersistenceAnnotation has been added to the resource. | ||
| // Annotations allow adding optional configuration or behavior. | ||
| if (redis.TryGetLastAnnotation<PersistenceAnnotation>(out var pa)) | ||
| { | ||
| // If persistence is configured, add the corresponding Redis CLI arguments. | ||
| var interval = (pa.Interval ?? TimeSpan.FromSeconds(60)) | ||
| .TotalSeconds | ||
| .ToString(CultureInfo.InvariantCulture); | ||
| cmd.Add("--save"); | ||
| cmd.Add(interval); // Save interval in seconds. | ||
| cmd.Add(pa.KeysChangedThreshold.ToString(CultureInfo.InvariantCulture)); // Number of key changes threshold. | ||
| } | ||
|
|
||
| // Finalize the arguments for the shell entrypoint. | ||
| context.Args.Add("-c"); // Argument for /bin/sh to execute a command string. | ||
| context.Args.Add(string.Join(' ', cmd)); // Join all parts into a single command string. | ||
| return Task.CompletedTask; // Return a completed task as the callback is synchronous. | ||
| }); | ||
| return redisBuilder |
| cache.OnResourceStopped( | ||
| static (resource, @event, ct) => | ||
| { | ||
| logger.LogInformation("Resource {Name} stopped", @event.Resource.Name); | ||
| var logger = @event.Services.GetRequiredService<ILogger<Program>>(); | ||
| logger.LogInformation("Resource {Name} stopped", resource.Name); | ||
| return Task.CompletedTask; | ||
| }); |
| s => s with { State = KnownResourceStates.Running }); | ||
| }); | ||
| builder.AddResource(myCustom) | ||
| .OnInitializeResource(async (resource, e, ct) => |
There was a problem hiding this comment.
OnInitializeResource first appears in release/9.4, but this is the 9.3 release page. Could you keep this example on builder.Eventing.Subscribe<InitializeResourceEvent>(...) so it remains valid for the version being documented?
| | `OnAfterPublish` | `AfterPublishEvent` — raised after manifest publishing completes | | ||
|
|
||
| For the full API surface, see the [.NET | ||
| `DistributedApplicationEventingExtensions`](https://learn.microsoft.com/dotnet/api/aspire.hosting.distributedapplicationeventingextensions) |
There was a problem hiding this comment.
This URL currently returns 404. We already expose the generated C# reference at /reference/api/csharp/aspire.hosting/distributedapplicationeventingextensions/; could you link that instead?
| builder.OnBeforeStart(async (e, ct) => { /* ... */ }); | ||
| // Run a callback once all resources have been created. | ||
| builder.SubscribeAfterResourcesCreated(async e => { /* ... */ }); | ||
| builder.OnAfterResourcesCreated(async (e, ct) => { /* ... */ }); |
There was a problem hiding this comment.
I don’t think OnAfterResourcesCreated exists in either release/13.3 or current Aspire; compiling this fails with CS1061. Could you keep this on builder.Eventing.Subscribe<AfterResourcesCreatedEvent>(...) and correct the matching helper row in eventing.mdx too?
Adam Ratzman (adamint)
left a comment
There was a problem hiding this comment.
Three docs correctness issues inline that I think should be fixed before merge: the dead .NET API link, the nonexistent OnAfterResourcesCreated helper, and a 9.4 helper on the 9.3 release page. These all look straightforward to address in place.
AppHost eventing docs still showed older
Eventing.Subscribe<T>patterns in places where typed helper APIs now exist. This updates the eventing guidance and related snippets to prefer the named helpers while keeping generic subscription examples only where the lower-level API is the point.AppHost eventing page
Related doc snippets
OnBeforeStartOnAfterResourcesCreatedOnInitializeResourceOnConnectionStringAvailableRelease notes and examples