Update Talking Clock example to use OnInitializeResource event#373
Update Talking Clock example to use OnInitializeResource event#373
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 pull request modernizes the Talking Clock custom resource example to use Aspire 9.3+ patterns, replacing obsolete lifecycle hooks with the event-based OnInitializeResource pattern.
Changes:
- Removed obsolete
IDistributedApplicationLifecycleHookandTalkingClockLifecycleHookclass in favor ofOnInitializeResourceevent - Added hierarchical resource structure with
ClockHandResourcechild resources demonstrating parent-child relationships - Updated API usage to use
WithUrlmethod instead ofWithInitialState.Urlsproperty
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| src/frontend/src/data/aspire-integrations.json | Unrelated automated updates to NuGet package download counts and versions |
| src/frontend/src/content/docs/architecture/resource-examples.mdx | Complete rewrite of Talking Clock example to demonstrate modern OnInitializeResource event pattern with hierarchical child resources |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // Enter the main loop that runs as long as cancellation is not requested. | ||
| while (!token.IsCancellationRequested) | ||
| { | ||
| // Log the current time, associated with the resource. | ||
| log.LogInformation("The time is {time}", DateTime.UtcNow); | ||
|
|
||
| // Publish a custom state update "Tick" using Aspire's ResourceStateSnapshot. | ||
| // This demonstrates using custom state strings and styles in the Aspire dashboard. | ||
| await notification.PublishUpdateAsync(resource, | ||
| s => s with { State = new ResourceStateSnapshot("Tick", KnownResourceStateStyles.Success) }); | ||
| await notification.PublishUpdateAsync(resource.TickHand, | ||
| s => s with { State = new ResourceStateSnapshot("On", KnownResourceStateStyles.Success) }); | ||
| await notification.PublishUpdateAsync(resource.TockHand, | ||
| s => s with { State = new ResourceStateSnapshot("Off", KnownResourceStateStyles.Info) }); | ||
|
|
||
| await Task.Delay(1000, token); | ||
|
|
||
| // Publish another custom state update "Tock" using Aspire's ResourceStateSnapshot. | ||
| await notification.PublishUpdateAsync(resource, | ||
| s => s with { State = new ResourceStateSnapshot("Tock", KnownResourceStateStyles.Success) }); | ||
| await notification.PublishUpdateAsync(resource.TickHand, | ||
| s => s with { State = new ResourceStateSnapshot("Off", KnownResourceStateStyles.Info) }); | ||
| await notification.PublishUpdateAsync(resource.TockHand, | ||
| s => s with { State = new ResourceStateSnapshot("On", KnownResourceStateStyles.Success) }); | ||
|
|
||
| await Task.Delay(1000, token); | ||
| } | ||
| }); |
There was a problem hiding this comment.
The background task started in OnInitializeResource runs an infinite loop without being properly managed. If the initialization completes but the task continues running, there's no mechanism to handle cancellation when the application shuts down gracefully. The task should be tracked or wrapped in a Task.Run to ensure it doesn't block initialization and can be properly cancelled.
Consider wrapping the loop logic in Task.Run to run it in the background without blocking the initialization event handler, similar to how it was done in the old lifecycle hook pattern.
| // Establish a parent-child relationship with the TalkingClockResource. | ||
| // This creates a hierarchical structure in the dashboard and coordinates lifecycle management. | ||
| .WithParentRelationship(clockBuilder) | ||
| .WithInitialState(new() |
There was a problem hiding this comment.
The WithInitialState call on line 352 uses new() without specifying the type explicitly. While this works in modern C#, for documentation purposes it would be clearer to explicitly specify new CustomResourceSnapshot() to match the pattern used on line 258 and help readers understand what type is being instantiated.
| .WithInitialState(new() | |
| .WithInitialState(new CustomResourceSnapshot |
The Talking Clock example demonstrated obsolete APIs (
IDistributedApplicationLifecycleHook,AfterResourcesCreatedAsync,BeforeResourceCreated) instead of the modernOnInitializeResourceevent pattern introduced in Aspire 9.3.Changes
Replaced lifecycle hook pattern with event-based initialization
TalkingClockLifecycleHookclass andTryAddLifecycleHookregistrationOnInitializeResourcecallback with direct access to logger, eventing, and notification servicesEnhanced with hierarchical resource structure
ClockHandResourcechild resources (tick/tock hands)WithParentRelationshipfor dashboard hierarchy and lifecycle coordinationModernized API usage
WithInitialStateUrls property withWithUrlmethodBefore
After
The example now demonstrates the recommended pattern for custom resources in Aspire 9.3+.
Warning
Firewall rules blocked me from connecting to one or more addresses (expand for details)
I tried to connect to the following addresses, but was blocked by firewall rules:
https://api.github.com/repos/CommunityToolkit/Aspire/home/REDACTED/work/_temp/ghcca-node/node/bin/node node ./scripts/update-github-stats.js(http block)/home/REDACTED/work/_temp/ghcca-node/node/bin/node node ./scripts/update-github-stats.js ire.dev/src/fron--pretty=format:������������ %H �� %aI �� %s �� %D �� %b �� %aN �� %aE ���� git log �� %aE ���� --follow /node-gyp-bin/git udes/config-settdirname --prune t git log �� %aE ���� --follow tend/node_modules/.bin/git udes/project-seash --follow tend/node_modulenode ./scripts/write-git-env.mjs git(http block)https://api.github.com/repos/CommunityToolkit/Aspire/contributors/home/REDACTED/work/_temp/ghcca-node/node/bin/node node /home/REDACTED/work/aspire.dev/aspire.dev/src/frontend/node_modules/.bin/../astro/astro.js build(http block)/home/REDACTED/work/_temp/ghcca-node/node/bin/node node /home/REDACTED/work/aspire.dev/aspire.dev/src/frontend/node_modules/.bin/../astro/astro.js build git log �� %aE ���� --follow s/.bin/git udes/option-debugit --all p/bin/git git log �� %aE ���� --follow /snap/bin/git all-script.mdx --follow odules/pnpm/distpnpm update:integrations && pnpm update:github-stats git(http block)https://api.github.com/repos/dotnet/aspire/home/REDACTED/work/_temp/ghcca-node/node/bin/node node ./scripts/update-github-stats.js(http block)/home/REDACTED/work/_temp/ghcca-node/node/bin/node node ./scripts/update-github-stats.js ire.dev/src/fron--pretty=format:������������ %H �� %aI �� %s �� %D �� %b �� %aN �� %aE ���� git log �� %aE ���� --follow /node-gyp-bin/git udes/config-settdirname --prune t git log �� %aE ���� --follow tend/node_modules/.bin/git udes/project-seash --follow tend/node_modulenode ./scripts/write-git-env.mjs git(http block)https://api.github.com/repos/dotnet/aspire-samples/home/REDACTED/work/_temp/ghcca-node/node/bin/node node ./scripts/update-github-stats.js(http block)/home/REDACTED/work/_temp/ghcca-node/node/bin/node node ./scripts/update-github-stats.js ire.dev/src/fron--pretty=format:������������ %H �� %aI �� %s �� %D �� %b �� %aN �� %aE ���� git log �� %aE ���� --follow /node-gyp-bin/git udes/config-settdirname --prune t git log �� %aE ���� --follow tend/node_modules/.bin/git udes/project-seash --follow tend/node_modulenode ./scripts/write-git-env.mjs git(http block)https://api.github.com/repos/dotnet/aspire-samples/contributors/home/REDACTED/work/_temp/ghcca-node/node/bin/node node /home/REDACTED/work/aspire.dev/aspire.dev/src/frontend/node_modules/.bin/../astro/astro.js build(http block)/home/REDACTED/work/_temp/ghcca-node/node/bin/node node /home/REDACTED/work/aspire.dev/aspire.dev/src/frontend/node_modules/.bin/../astro/astro.js build git log �� %aE ���� --follow s/.bin/git udes/option-debugit --all p/bin/git git log �� %aE ���� --follow /snap/bin/git all-script.mdx --follow odules/pnpm/distpnpm update:integrations && pnpm update:github-stats git(http block)https://api.github.com/repos/dotnet/aspire/contributors/home/REDACTED/work/_temp/ghcca-node/node/bin/node node /home/REDACTED/work/aspire.dev/aspire.dev/src/frontend/node_modules/.bin/../astro/astro.js build(http block)/home/REDACTED/work/_temp/ghcca-node/node/bin/node node /home/REDACTED/work/aspire.dev/aspire.dev/src/frontend/node_modules/.bin/../astro/astro.js build git log �� %aE ���� --follow s/.bin/git udes/option-debugit --all p/bin/git git log �� %aE ���� --follow /snap/bin/git all-script.mdx --follow odules/pnpm/distpnpm update:integrations && pnpm update:github-stats git(http block)https://api.github.com/repos/microsoft/aspire.dev/home/REDACTED/work/_temp/ghcca-node/node/bin/node node ./scripts/update-github-stats.js(http block)/home/REDACTED/work/_temp/ghcca-node/node/bin/node node ./scripts/update-github-stats.js ire.dev/src/fron--pretty=format:������������ %H �� %aI �� %s �� %D �� %b �� %aN �� %aE ���� git log �� %aE ���� --follow /node-gyp-bin/git udes/config-settdirname --prune t git log �� %aE ���� --follow tend/node_modules/.bin/git udes/project-seash --follow tend/node_modulenode ./scripts/write-git-env.mjs git(http block)https://api.github.com/repos/microsoft/aspire.dev/contributors/home/REDACTED/work/_temp/ghcca-node/node/bin/node node /home/REDACTED/work/aspire.dev/aspire.dev/src/frontend/node_modules/.bin/../astro/astro.js build(http block)/home/REDACTED/work/_temp/ghcca-node/node/bin/node node /home/REDACTED/work/aspire.dev/aspire.dev/src/frontend/node_modules/.bin/../astro/astro.js build git log �� %aE ���� --follow s/.bin/git udes/option-debugit --all p/bin/git git log �� %aE ���� --follow /snap/bin/git all-script.mdx --follow odules/pnpm/distpnpm update:integrations && pnpm update:github-stats git(http block)https://api.github.com/repos/microsoft/dcp/home/REDACTED/work/_temp/ghcca-node/node/bin/node node ./scripts/update-github-stats.js(http block)/home/REDACTED/work/_temp/ghcca-node/node/bin/node node ./scripts/update-github-stats.js ire.dev/src/fron--pretty=format:������������ %H �� %aI �� %s �� %D �� %b �� %aN �� %aE ���� git log �� %aE ���� --follow /node-gyp-bin/git udes/config-settdirname --prune t git log �� %aE ���� --follow tend/node_modules/.bin/git udes/project-seash --follow tend/node_modulenode ./scripts/write-git-env.mjs git(http block)https://api.github.com/repos/microsoft/dcp/contributors/home/REDACTED/work/_temp/ghcca-node/node/bin/node node /home/REDACTED/work/aspire.dev/aspire.dev/src/frontend/node_modules/.bin/../astro/astro.js build(http block)/home/REDACTED/work/_temp/ghcca-node/node/bin/node node /home/REDACTED/work/aspire.dev/aspire.dev/src/frontend/node_modules/.bin/../astro/astro.js build git log �� %aE ���� --follow s/.bin/git udes/option-debugit --all p/bin/git git log �� %aE ���� --follow /snap/bin/git all-script.mdx --follow odules/pnpm/distpnpm update:integrations && pnpm update:github-stats git(http block)learn.microsoft.com/home/REDACTED/work/_temp/ghcca-node/node/bin/node node /home/REDACTED/work/aspire.dev/aspire.dev/src/frontend/node_modules/.bin/../astro/astro.js build(dns block)/home/REDACTED/work/_temp/ghcca-node/node/bin/node node /home/REDACTED/work/aspire.dev/aspire.dev/src/frontend/node_modules/.bin/../astro/astro.js build git log �� %aE ���� --follow s/.bin/git udes/option-debugit --all p/bin/git git log �� %aE ���� --follow /snap/bin/git all-script.mdx --follow odules/pnpm/distpnpm update:integrations && pnpm update:github-stats git(dns block)telemetry.astro.build/home/REDACTED/work/_temp/ghcca-node/node/bin/node node /home/REDACTED/work/aspire.dev/aspire.dev/src/frontend/node_modules/.bin/../astro/astro.js build(dns block)/home/REDACTED/work/_temp/ghcca-node/node/bin/node node /home/REDACTED/work/aspire.dev/aspire.dev/src/frontend/node_modules/.bin/../astro/astro.js build /usr/lib/git-cor--follow remo�� �� %aE ���� REDACTED cal/bin/git rch-logic-descrigit --fix-thin /node-gyp-bin/gi--pretty=format:������������ %H �� %aI �� %s �� %D �� %b �� %aN �� %aE ���� git log �� %aE ���� --follow odules/pnpm/dist/node-gyp-bin/git ands/aspire-publgit --follow t git(dns block)/home/REDACTED/work/_temp/ghcca-node/node/bin/node node /home/REDACTED/work/aspire.dev/aspire.dev/src/frontend/node_modules/.bin/../astro/astro.js build git log �� %aE ���� --follow s/.bin/git udes/option-debugit --all p/bin/git git log �� %aE ���� --follow /snap/bin/git all-script.mdx --follow odules/pnpm/distpnpm update:integrations && pnpm update:github-stats git(dns block)If you need me to access, download, or install something from one of these locations, you can either:
Original prompt
💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.