AppHost eventing APIs
यह कंटेंट अभी तक आपकी भाषा में उपलब्ध नहीं है।
In Aspire, eventing allows you to publish and subscribe to events during various AppHost life cycles. Eventing is more flexible than life cycle events. Both let you run arbitrary code during event callbacks, but eventing offers finer control of event timing, publishing, and provides supports for custom events.
AppHost eventing
Section titled “AppHost eventing”The following events are available in the AppHost and occur in the following order:
BeforeStartEvent: This event is raised before the AppHost starts.ResourceEndpointsAllocatedEvent: This event is raised per resource after its endpoints are allocated.AfterResourcesCreatedEvent: This event is raised after resources are created.
Subscribe to AppHost events
Section titled “Subscribe to AppHost events”To subscribe to built-in AppHost events, use the typed API available for each event. C# provides builder extension methods for selected events and the lower-level Eventing.Subscribe<T>() API for others. TypeScript provides named subscription methods:
import { function createBuilder(): IDistributedApplicationBuilder
Creates a new distributed application builder
createBuilder } from './.aspire/modules/aspire.mjs';
const const builder: IDistributedApplicationBuilder
builder = await function createBuilder(): IDistributedApplicationBuilder
Creates a new distributed application builder
createBuilder();
await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.subscribeBeforeStart(callback: (arg: BeforeStartEvent) => Promise<void>): DistributedApplicationEventSubscription
Subscribes to the BeforeStart event, which fires before the application starts.
subscribeBeforeStart(async () => { var console: Console
console.Console.log(...data: any[]): void
The console.log() static method outputs a message to the console.
log('BeforeStartEvent');});
await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.subscribeAfterResourcesCreated(callback: (arg: AfterResourcesCreatedEvent) => Promise<void>): DistributedApplicationEventSubscription
Subscribes to the AfterResourcesCreated event, which fires after all resources are created.
subscribeAfterResourcesCreated(async () => { var console: Console
console.Console.log(...data: any[]): void
The console.log() static method outputs a message to the console.
log('AfterResourcesCreatedEvent');});
await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.build(): DistributedApplication
Builds the distributed application
build().DistributedApplication.run(cancellationToken?: cancellationToken): void
Runs the distributed application
run();using Microsoft.Extensions.DependencyInjection;using Microsoft.Extensions.Logging;
var builder = DistributedApplication.CreateBuilder(args);
builder.OnBeforeStart(static (@event, cancellationToken) =>{ var logger = @event.Services.GetRequiredService<ILogger<Program>>(); logger.LogInformation("BeforeStartEvent"); return Task.CompletedTask;});
builder.Eventing.Subscribe<AfterResourcesCreatedEvent>( static (@event, cancellationToken) => { var logger = @event.Services.GetRequiredService<ILogger<Program>>(); logger.LogInformation("AfterResourcesCreatedEvent"); return Task.CompletedTask; });
builder.Build().Run();The following C# builder-level helper methods are available for AppHost events:
| Method | Event |
|---|---|
OnBeforeStart | BeforeStartEvent — raised before the AppHost starts |
OnBeforePublish | BeforePublishEvent — raised before manifest publishing begins |
OnAfterPublish | AfterPublishEvent — raised after manifest publishing completes |
For the full API surface, see the C# DistributedApplicationEventingExtensions API reference
and the TypeScript Aspire.Hosting API reference.
If you need to subscribe via IDistributedApplicationEventing directly (for example, inside an IDistributedApplicationEventingSubscriber), you can use the lower-level Eventing.Subscribe<T>() API:
builder.Eventing.Subscribe<BeforeStartEvent>( static (@event, cancellationToken) => { var logger = @event.Services.GetRequiredService<ILogger<Program>>(); logger.LogInformation("BeforeStartEvent"); return Task.CompletedTask; });
builder.Eventing.Subscribe<AfterResourcesCreatedEvent>( static (@event, cancellationToken) => { var logger = @event.Services.GetRequiredService<ILogger<Program>>(); logger.LogInformation("AfterResourcesCreatedEvent"); return Task.CompletedTask; });When the AppHost is run, by the time the Aspire dashboard is displayed, you should see the following log output in the console:
info: Program[0] BeforeStartEventinfo: Aspire.Hosting.DistributedApplication[0] Aspire version: 13.6.0info: Aspire.Hosting.DistributedApplication[0] Distributed application starting.info: Aspire.Hosting.DistributedApplication[0] Application host directory is: ../AspireApp/AspireApp.AppHostinfo: Aspire.Hosting.DistributedApplication[0] Now listening on: https://localhost:17178info: Aspire.Hosting.DistributedApplication[0] Login to the dashboard at https://localhost:17178/login?t=<YOUR_TOKEN>info: Program[0] AfterResourcesCreatedEventinfo: Aspire.Hosting.DistributedApplication[0] Distributed application started. Press Ctrl+C to shut down.The log output confirms that event handlers are executed in the order of the AppHost life cycle events. The subscription order doesn’t affect execution order. The BeforeStartEvent is triggered before the AppHost starts, and AfterResourcesCreatedEvent is triggered after resources are created.
Resource eventing
Section titled “Resource eventing”In addition to the AppHost events, you can also subscribe to resource events. Resource events are raised specific to an individual resource. Resource events are defined as implementations of the IDistributedApplicationResourceEvent interface. The following resource events are available in the listed order:
InitializeResourceEvent: Raised by orchestrators to signal to resources that they should initialize themselves.ResourceEndpointsAllocatedEvent: Raised when the orchestrator allocates endpoints for a resource.ConnectionStringAvailableEvent: Raised when a connection string becomes available for a resource.BeforeResourceStartedEvent: Raised before the orchestrator starts a new resource.ResourceReadyEvent: Raised when a resource initially transitions to a ready state.
Subscribe to resource events
Section titled “Subscribe to resource events”To subscribe to resource events, use the convenience-based extension methods. After you have a distributed application builder instance, and a resource builder, walk up to the instance and chain a call to the desired event API:
import { function createBuilder(): IDistributedApplicationBuilder
Creates a new distributed application builder
createBuilder } from './.aspire/modules/aspire.mjs';
const const builder: IDistributedApplicationBuilder
builder = await function createBuilder(): IDistributedApplicationBuilder
Creates a new distributed application builder
createBuilder();
const const cache: RedisResource
cache = await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.addRedis(name: string, options?: { port?: number; password?: string | ParameterResource;}): RedisResource (+1 overload)
Adds a Redis container to the application model.
addRedis('cache');
await const cache: RedisResource
cache.ContainerResource.onInitializeResource(callback: (arg: InitializeResourceEvent) => Promise<void>): RedisResource
Subscribes to the InitializeResource event.
onInitializeResource(async () => { var console: Console
console.Console.log(...data: any[]): void
The console.log() static method outputs a message to the console.
log('1. onInitializeResource');});
await const cache: RedisResource
cache.ContainerResource.onResourceEndpointsAllocated(callback: (arg: ResourceEndpointsAllocatedEvent) => Promise<void>): RedisResource
Subscribes to the ResourceEndpointsAllocated event.
onResourceEndpointsAllocated(async (event: ResourceEndpointsAllocatedEvent
event) => { const const resource: IResource
resource = await event: ResourceEndpointsAllocatedEvent
event.ResourceEndpointsAllocatedEvent.resource: () => Promise<IResource>
Gets the Resource property
resource(); var console: Console
console.Console.log(...data: any[]): void
The console.log() static method outputs a message to the console.
log(`2. endpoints allocated for ${const resource: IResource
resource.IResource.getResourceName(): string
Gets the name of the resource from a builder.
getResourceName()}`);});
await const cache: RedisResource
cache.IResourceWithConnectionString.onConnectionStringAvailable(callback: (arg: ConnectionStringAvailableEvent) => Promise<void>): RedisResource
Subscribes to the ConnectionStringAvailable event.
onConnectionStringAvailable(async (event: ConnectionStringAvailableEvent
event) => { const const resource: IResource
resource = await event: ConnectionStringAvailableEvent
event.ConnectionStringAvailableEvent.resource: () => Promise<IResource>
Gets the Resource property
resource(); var console: Console
console.Console.log(...data: any[]): void
The console.log() static method outputs a message to the console.
log( `3. connection string available for ${const resource: IResource
resource.IResource.getResourceName(): string
Gets the name of the resource from a builder.
getResourceName()}` );});
await const cache: RedisResource
cache.ContainerResource.onBeforeResourceStarted(callback: (arg: BeforeResourceStartedEvent) => Promise<void>): RedisResource
Subscribes to the BeforeResourceStarted event.
onBeforeResourceStarted(async () => { var console: Console
console.Console.log(...data: any[]): void
The console.log() static method outputs a message to the console.
log('4. onBeforeResourceStarted');});
await const cache: RedisResource
cache.ContainerResource.onResourceReady(callback: (arg: ResourceReadyEvent) => Promise<void>): RedisResource
Subscribes to the ResourceReady event.
onResourceReady(async () => { var console: Console
console.Console.log(...data: any[]): void
The console.log() static method outputs a message to the console.
log('5. onResourceReady');});
await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.build(): DistributedApplication
Builds the distributed application
build().DistributedApplication.run(cancellationToken?: cancellationToken): void
Runs the distributed application
run();using Microsoft.Extensions.DependencyInjection;using Microsoft.Extensions.Logging;
var builder = DistributedApplication.CreateBuilder(args);
var cache = builder.AddRedis("cache");
cache.OnResourceReady(static (resource, @event, cancellationToken) => { var logger = @event.Services.GetRequiredService<ILogger<Program>>(); logger.LogInformation("5. OnResourceReady");
return Task.CompletedTask; });
cache.OnInitializeResource( static (resource, @event, cancellationToken) => { var logger = @event.Services.GetRequiredService<ILogger<Program>>(); logger.LogInformation("1. OnInitializeResource");
return Task.CompletedTask; });
cache.OnBeforeResourceStarted( static (resource, @event, cancellationToken) => { var logger = @event.Services.GetRequiredService<ILogger<Program>>(); logger.LogInformation("4. OnBeforeResourceStarted");
return Task.CompletedTask; });
cache.OnResourceEndpointsAllocated( static (resource, @event, cancellationToken) => { var logger = @event.Services.GetRequiredService<ILogger<Program>>(); logger.LogInformation("2. OnResourceEndpointsAllocated");
return Task.CompletedTask; });
cache.OnConnectionStringAvailable( static (resource, @event, cancellationToken) => { var logger = @event.Services.GetRequiredService<ILogger<Program>>(); logger.LogInformation("3. OnConnectionStringAvailable");
return Task.CompletedTask; });
var apiService = builder.AddProject<Projects.AspireApp_ApiService>("apiservice");
builder.AddProject<Projects.AspireApp_Web>("webfrontend") .WithExternalHttpEndpoints() .WithReference(cache) .WaitFor(cache) .WithReference(apiService) .WaitFor(apiService);
builder.Build().Run();The preceding code subscribes to the InitializeResourceEvent, ResourceReadyEvent, ResourceEndpointsAllocatedEvent, ConnectionStringAvailableEvent, and BeforeResourceStartedEvent events on the cache resource. Chain calls to the event methods to subscribe to multiple events on the same resource.
OnInitializeResourceonInitializeResource: Subscribes to theInitializeResourceEvent.OnResourceEndpointsAllocatedonResourceEndpointsAllocated: Subscribes to theResourceEndpointsAllocatedEventevent.OnConnectionStringAvailableonConnectionStringAvailable: Subscribes to theConnectionStringAvailableEventevent.OnBeforeResourceStartedonBeforeResourceStarted: Subscribes to theBeforeResourceStartedEventevent.OnResourceReady/onResourceReady: Subscribes to theResourceReadyEventevent.OnResourceStoppedonResourceStopped: Subscribes to theResourceStoppedEventevent.
When the AppHost is run, by the time the Aspire dashboard is displayed, you should see the following log output in the console:
info: Aspire.Hosting.DistributedApplication[0] Aspire version: 13.6.0info: Aspire.Hosting.DistributedApplication[0] Distributed application starting.info: Aspire.Hosting.DistributedApplication[0] Application host directory is: ../AspireApp/AspireApp.AppHostinfo: Program[0] 1. OnInitializeResourceinfo: Program[0] 2. OnResourceEndpointsAllocatedinfo: Program[0] 3. OnConnectionStringAvailableinfo: Program[0] 4. OnBeforeResourceStartedinfo: Aspire.Hosting.DistributedApplication[0] Now listening on: https://localhost:17222info: Aspire.Hosting.DistributedApplication[0] Login to the dashboard at https://localhost:17222/login?t=<YOUR_TOKEN>info: Program[0] 5. OnResourceReadyinfo: Aspire.Hosting.DistributedApplication[0] Distributed application started. Press Ctrl+C to shut down.Publish events
Section titled “Publish events”When subscribing to any of the built-in events, you don’t need to publish the event yourself as the AppHost orchestrator manages to publish built-in events on your behalf. However, you can publish custom events with the eventing API. To publish an event, you have to first define an event as an implementation of either the IDistributedApplicationEvent or IDistributedApplicationResourceEvent interface. You need to determine which interface to implement based on whether the event is a global AppHost event or a resource-specific event.
Then, you can subscribe and publish the event by calling the either of the following APIs:
PublishAsync<T>(T, CancellationToken): Publishes an event to all subscribes of the specific event type.PublishAsync<T>(T, EventDispatchBehavior, CancellationToken): Publishes an event to all subscribes of the specific event type with a specified dispatch behavior.
Provide an EventDispatchBehavior
Section titled “Provide an EventDispatchBehavior”When events are dispatched, you can control how the events are dispatched to subscribers. The event dispatch behavior is specified with the EventDispatchBehavior enum. The following behaviors are available:
EventDispatchBehavior.BlockingSequential: Fires events sequentially and blocks until they’re all processed.EventDispatchBehavior.BlockingConcurrent: Fires events concurrently and blocks until they’re all processed.EventDispatchBehavior.NonBlockingSequential: Fires events sequentially but doesn’t block.EventDispatchBehavior.NonBlockingConcurrent: Fires events concurrently but doesn’t block.
The default behavior is EventDispatchBehavior.BlockingSequential. To override this behavior, when calling a publishing API such as PublishAsync, provide the desired behavior as an argument.
Eventing subscribers
Section titled “Eventing subscribers”In some cases, such as extension libraries, you may need to access lifecycle events from a service rather than directly from the Aspire application model. You can implement IDistributedApplicationEventingSubscriber and register the service with AddEventingSubscriber (or TryAddEventingSubscriber if you want to avoid duplicate registrations).
using Aspire.Hosting.Eventing;using Aspire.Hosting.Lifecycle;using Microsoft.Extensions.DependencyInjection;using Microsoft.Extensions.Logging;
var builder = DistributedApplication.CreateBuilder(args);
builder.Services.AddEventingSubscriber<LifecycleLoggerSubscriber>();
builder.Build().Run();
internal sealed class LifecycleLoggerSubscriber(ILogger<LifecycleLoggerSubscriber> logger) : IDistributedApplicationEventingSubscriber{ public Task SubscribeAsync( IDistributedApplicationEventing eventing, DistributedApplicationExecutionContext executionContext, CancellationToken cancellationToken) { eventing.Subscribe<BeforeStartEvent>((@event, ct) => { logger.LogInformation("1. BeforeStartEvent"); return Task.CompletedTask; });
eventing.Subscribe<ResourceEndpointsAllocatedEvent>((@event, ct) => { logger.LogInformation("2. {Resource} ResourceEndpointsAllocatedEvent", @event.Resource.Name); return Task.CompletedTask; });
eventing.Subscribe<AfterResourcesCreatedEvent>((@event, ct) => { logger.LogInformation("3. AfterResourcesCreatedEvent"); return Task.CompletedTask; });
return Task.CompletedTask; }}import { function createBuilder(): IDistributedApplicationBuilder
Creates a new distributed application builder
createBuilder } from './.aspire/modules/aspire.mjs';
const const builder: IDistributedApplicationBuilder
builder = await function createBuilder(): IDistributedApplicationBuilder
Creates a new distributed application builder
createBuilder();
const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.addEventingSubscriber(subscribe: (arg: EventingSubscriberRegistrationContext) => Promise<void>): void
Adds an ATS-friendly eventing subscriber callback to the distributed-application builder.
addEventingSubscriber(async (events: EventingSubscriberRegistrationContext
events) => { events: EventingSubscriberRegistrationContext
events.EventingSubscriberRegistrationContext.onBeforeStart(callback: (arg: BeforeStartEvent) => Promise<void>): DistributedApplicationEventSubscription
Subscribes to the BeforeStart event from an eventing subscriber registration context.
onBeforeStart(async () => { var console: Console
console.Console.log(...data: any[]): void
The console.log() static method outputs a message to the console.
log('1. BeforeStartEvent'); });
events: EventingSubscriberRegistrationContext
events.EventingSubscriberRegistrationContext.onAfterResourcesCreated(callback: (arg: AfterResourcesCreatedEvent) => Promise<void>): DistributedApplicationEventSubscription
Subscribes to the AfterResourcesCreated event from an eventing subscriber registration context.
onAfterResourcesCreated(async () => { var console: Console
console.Console.log(...data: any[]): void
The console.log() static method outputs a message to the console.
log('3. AfterResourcesCreatedEvent'); });});
await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.build(): DistributedApplication
Builds the distributed application
build().DistributedApplication.run(cancellationToken?: cancellationToken): void
Runs the distributed application
run();The subscriber approach keeps builder code minimal while still letting you respond to the same lifecycle moments as inline subscriptions:
AddEventingSubscriber<T>()(orTryAddEventingSubscriber()) ensures the subscriber participates whenever the AppHost starts.SubscribeAsyncis called once per AppHost execution, giving you access toIDistributedApplicationEventingand theDistributedApplicationExecutionContextshould you need model- or environment-specific data.- You can register handlers for any built-in event (AppHost or resource) or for your own custom
IDistributedApplicationEventtypes.
Use this pattern whenever you previously relied on IDistributedApplicationLifecycleHook. The lifecycle hook APIs remain only for backward compatibility and will be removed in a future release.
Migrating from lifecycle hooks
Section titled “Migrating from lifecycle hooks”If you’re migrating from the deprecated IDistributedApplicationLifecycleHook interface, use the following mapping:
| Old pattern (deprecated) | New pattern |
|---|---|
BeforeStartAsync() | Subscribe to BeforeStartEvent |
AfterEndpointsAllocatedAsync() | Subscribe to ResourceEndpointsAllocatedEvent |
AfterResourcesCreatedAsync() | Subscribe to AfterResourcesCreatedEvent |
TryAddLifecycleHook<T>() | TryAddEventingSubscriber<T>() |
Before (deprecated):
public class MyHook : IDistributedApplicationLifecycleHook{ public Task AfterResourcesCreatedAsync( DistributedApplicationModel model, CancellationToken cancellationToken) { // Handle event return Task.CompletedTask; }}
// Registrationbuilder.Services.TryAddLifecycleHook<MyHook>();After (recommended):
public class MySubscriber : IDistributedApplicationEventingSubscriber{ public Task SubscribeAsync( IDistributedApplicationEventing eventing, DistributedApplicationExecutionContext context, CancellationToken cancellationToken) { eventing.Subscribe<AfterResourcesCreatedEvent>((@event, ct) => { // Handle event using context.Model return Task.CompletedTask; });
return Task.CompletedTask; }}
// Registrationbuilder.Services.TryAddEventingSubscriber<MySubscriber>();Additional events
Section titled “Additional events”Beyond the core lifecycle events, Aspire provides additional events for specific scenarios:
Publishing events
Section titled “Publishing events”When publishing your application (generating deployment manifests), these events are raised:
| Event | When raised | Purpose |
|---|---|---|
BeforePublishEvent | Before publishing begins | Validate or modify resources before manifest generation |
AfterPublishEvent | After publishing completes | Perform cleanup or post-publish actions |
import { function createBuilder(): IDistributedApplicationBuilder
Creates a new distributed application builder
createBuilder } from './.aspire/modules/aspire.mjs';
const const builder: IDistributedApplicationBuilder
builder = await function createBuilder(): IDistributedApplicationBuilder
Creates a new distributed application builder
createBuilder();
await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.subscribeBeforePublish(callback: (arg: BeforePublishEvent) => Promise<void>): DistributedApplicationEventSubscription (+1 overload)
Subscribes to the BeforePublish event
subscribeBeforePublish(async (event: BeforePublishEvent
event) => { const const model: DistributedApplicationModel
model = await event: BeforePublishEvent
event.BeforePublishEvent.model: () => Promise<DistributedApplicationModel>
The DistributedApplicationModel instance.
model(); var console: Console
console.Console.log(...data: any[]): void
The console.log() static method outputs a message to the console.
log(`Publishing ${const model: DistributedApplicationModel
model.DistributedApplicationModel.getResources(): IResource[]
Gets all resources in the distributed application model.
getResources().Array<IResource>.length: number
Gets or sets the length of the array. This is a number one higher than the highest index in the array.
length} resources`);});
await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.subscribeAfterPublish(callback: (arg: AfterPublishEvent) => Promise<void>): DistributedApplicationEventSubscription (+1 overload)
Subscribes to the AfterPublish event
subscribeAfterPublish(async (event: AfterPublishEvent
event) => { const const services: IServiceProvider
services = await event: AfterPublishEvent
event.AfterPublishEvent.services: () => Promise<IServiceProvider>
The IServiceProvider for the AppHost.
services(); var console: Console
console.Console.log(...data: any[]): void
The console.log() static method outputs a message to the console.
log('Publish completed', const services: IServiceProvider
services);});builder.OnBeforePublish((@event, ct) =>{ // Validate resources before publishing return Task.CompletedTask;});
builder.OnAfterPublish((@event, ct) =>{ // Post-publish actions return Task.CompletedTask;});For details on what happens during publishing, see Publishing and deployment overview.
Resource stopped event
Section titled “Resource stopped event”The ResourceStoppedEvent is raised once each time a resource stops execution.
If a handler restarts the resource, the restart doesn’t raise another event for
the same stop. The event is raised again only when the resource subsequently
stops:
import { function createBuilder(): IDistributedApplicationBuilder
Creates a new distributed application builder
createBuilder } from './.aspire/modules/aspire.mjs';
const const builder: IDistributedApplicationBuilder
builder = await function createBuilder(): IDistributedApplicationBuilder
Creates a new distributed application builder
createBuilder();
const const cache: RedisResource
cache = await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.addRedis(name: string, options?: { port?: number; password?: string | ParameterResource;}): RedisResource (+1 overload)
Adds a Redis container to the application model.
addRedis('cache');
await const cache: RedisResource
cache.ContainerResource.onResourceStopped(callback: (arg: ResourceStoppedEvent) => Promise<void>): RedisResource
Subscribes to the ResourceStopped event.
onResourceStopped(async (event: ResourceStoppedEvent
event) => { const const resource: IResource
resource = await event: ResourceStoppedEvent
event.ResourceStoppedEvent.resource: () => Promise<IResource>
Gets the Resource property
resource(); var console: Console
console.Console.log(...data: any[]): void
The console.log() static method outputs a message to the console.
log(`Resource ${const resource: IResource
resource.IResource.getResourceName(): string
Gets the name of the resource from a builder.
getResourceName()} stopped`);});using Microsoft.Extensions.DependencyInjection;using Microsoft.Extensions.Logging;
var builder = DistributedApplication.CreateBuilder(args);
var cache = builder.AddRedis("cache");
cache.OnResourceStopped( static (resource, @event, ct) => { var logger = @event.Services.GetRequiredService<ILogger<Program>>(); logger.LogInformation("Resource {Name} stopped", resource.Name); return Task.CompletedTask; });
builder.Build().Run();