Skip to content

Update Talking Clock example to use OnInitializeResource event#373

Open
Copilot wants to merge 3 commits intomainfrom
copilot/update-talking-clock-example
Open

Update Talking Clock example to use OnInitializeResource event#373
Copilot wants to merge 3 commits intomainfrom
copilot/update-talking-clock-example

Conversation

Copy link
Contributor

Copilot AI commented Feb 5, 2026

The Talking Clock example demonstrated obsolete APIs (IDistributedApplicationLifecycleHook, AfterResourcesCreatedAsync, BeforeResourceCreated) instead of the modern OnInitializeResource event pattern introduced in Aspire 9.3.

Changes

  • Replaced lifecycle hook pattern with event-based initialization

    • Removed TalkingClockLifecycleHook class and TryAddLifecycleHook registration
    • Added OnInitializeResource callback with direct access to logger, eventing, and notification services
  • Enhanced with hierarchical resource structure

    • Added ClockHandResource child resources (tick/tock hands)
    • Demonstrated WithParentRelationship for dashboard hierarchy and lifecycle coordination
  • Modernized API usage

Before

builder.Services.TryAddLifecycleHook<TalkingClockLifecycleHook>();
var clockResource = new TalkingClockResource(name);

After

var clockResource = new TalkingClockResource(name, tickHandResource, tockHandResource);
clockBuilder.OnInitializeResource(static async (resource, @event, token) =>
{
    var log = @event.Logger;
    var notification = @event.Notifications;
    // Initialize resource lifecycle directly
});

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
    • Triggering command: /home/REDACTED/work/_temp/ghcca-node/node/bin/node node ./scripts/update-github-stats.js (http block)
    • Triggering command: /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
    • Triggering command: /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)
    • Triggering command: /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 &amp;&amp; pnpm update:github-stats git (http block)
  • https://api.github.com/repos/dotnet/aspire
    • Triggering command: /home/REDACTED/work/_temp/ghcca-node/node/bin/node node ./scripts/update-github-stats.js (http block)
    • Triggering command: /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
    • Triggering command: /home/REDACTED/work/_temp/ghcca-node/node/bin/node node ./scripts/update-github-stats.js (http block)
    • Triggering command: /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
    • Triggering command: /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)
    • Triggering command: /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 &amp;&amp; pnpm update:github-stats git (http block)
  • https://api.github.com/repos/dotnet/aspire/contributors
    • Triggering command: /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)
    • Triggering command: /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 &amp;&amp; pnpm update:github-stats git (http block)
  • https://api.github.com/repos/microsoft/aspire.dev
    • Triggering command: /home/REDACTED/work/_temp/ghcca-node/node/bin/node node ./scripts/update-github-stats.js (http block)
    • Triggering command: /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
    • Triggering command: /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)
    • Triggering command: /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 &amp;&amp; pnpm update:github-stats git (http block)
  • https://api.github.com/repos/microsoft/dcp
    • Triggering command: /home/REDACTED/work/_temp/ghcca-node/node/bin/node node ./scripts/update-github-stats.js (http block)
    • Triggering command: /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
    • Triggering command: /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)
    • Triggering command: /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 &amp;&amp; pnpm update:github-stats git (http block)
  • learn.microsoft.com
    • Triggering command: /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)
    • Triggering command: /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 &amp;&amp; pnpm update:github-stats git (dns block)
  • telemetry.astro.build
    • Triggering command: /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)
    • Triggering command: /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)
    • Triggering command: /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 &amp;&amp; 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

This section details on the original issue you should resolve

<issue_title>Talking Clock Example is outdated</issue_title>
<issue_description>The talking clock example at https://aspire.dev/architecture/resource-examples/#example-custom-resource---talking-clock is oudated

  • It uses obsolete LifecycleHooks
  • It uses the obsolete BeforeResoruceCreated event
  • It doesn't demonstrate the OnInitializeResource event which is specifically for custom resources.

Latest version is at https://github.com/dotnet/aspire/blob/main/playground/CustomResources/CustomResources.AppHost/TalkingClockResource.cs</issue_description>

Comments on the Issue (you are @copilot in this section)


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

Copilot AI and others added 2 commits February 5, 2026 14:11
Co-authored-by: IEvangelist <7679720+IEvangelist@users.noreply.github.com>
Co-authored-by: IEvangelist <7679720+IEvangelist@users.noreply.github.com>
Copilot AI changed the title [WIP] Update outdated talking clock example Update Talking Clock example to use OnInitializeResource event Feb 5, 2026
Copilot AI requested a review from IEvangelist February 5, 2026 14:20
@IEvangelist IEvangelist marked this pull request as ready for review February 5, 2026 14:59
Copilot AI review requested due to automatic review settings February 5, 2026 14:59
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 IDistributedApplicationLifecycleHook and TalkingClockLifecycleHook class in favor of OnInitializeResource event
  • Added hierarchical resource structure with ClockHandResource child resources demonstrating parent-child relationships
  • Updated API usage to use WithUrl method instead of WithInitialState.Urls property

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.

Comment on lines +312 to +339
// 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);
}
});
Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
// Establish a parent-child relationship with the TalkingClockResource.
// This creates a hierarchical structure in the dashboard and coordinates lifecycle management.
.WithParentRelationship(clockBuilder)
.WithInitialState(new()
Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
.WithInitialState(new()
.WithInitialState(new CustomResourceSnapshot

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Talking Clock Example is outdated

2 participants