Skip to content
18 changes: 14 additions & 4 deletions playground/CustomResources/CustomResources.AppHost/TestResource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System.Globalization;
using Aspire.Hosting.Eventing;
using Aspire.Hosting.Lifecycle;
using Microsoft.Extensions.Logging;

static class TestResourceExtensions
{
public static IResourceBuilder<TestResource> AddTestResource(this IDistributedApplicationBuilder builder, string name)
{
builder.Services.TryAddLifecycleHook<TestResourceLifecycleHook>();
builder.Services.TryAddEventingSubscriber<TestResourceLifecycle>();

var rb = builder.AddResource(new TestResource(name))
.WithInitialState(new()
Expand All @@ -27,13 +28,16 @@ public static IResourceBuilder<TestResource> AddTestResource(this IDistributedAp
}
}

internal sealed class TestResourceLifecycleHook(ResourceNotificationService notificationService, ResourceLoggerService loggerService) : IDistributedApplicationLifecycleHook, IAsyncDisposable
internal sealed class TestResourceLifecycle(
ResourceNotificationService notificationService,
ResourceLoggerService loggerService
) : IDistributedApplicationEventingSubscriber
{
private readonly CancellationTokenSource _tokenSource = new();

public Task BeforeStartAsync(DistributedApplicationModel appModel, CancellationToken cancellationToken = default)
public Task OnBeforeStartAsync(BeforeStartEvent @event, CancellationToken cancellationToken = default)
{
foreach (var resource in appModel.Resources.OfType<TestResource>())
foreach (var resource in @event.Model.Resources.OfType<TestResource>())
{
var states = new[] { "Starting", "Running", "Finished", "Uploading", "Downloading", "Processing", "Provisioning" };
var stateStyles = new[] { "info", "success", "warning", "error" };
Expand Down Expand Up @@ -76,6 +80,12 @@ public ValueTask DisposeAsync()
_tokenSource.Cancel();
return default;
}

public Task Subscribe(IDistributedApplicationEventing eventing, DistributedApplicationExecutionContext executionContext, CancellationToken cancellationToken)
{
eventing.Subscribe<BeforeStartEvent>(OnBeforeStartAsync);
return Task.CompletedTask;
}
}

sealed class TestResource(string name) : Resource(name)
Expand Down
15 changes: 11 additions & 4 deletions playground/HealthChecks/HealthChecksSandbox.AppHost/Program.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Aspire.Hosting.Eventing;
using Aspire.Hosting.Lifecycle;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Diagnostics.HealthChecks;

var builder = DistributedApplication.CreateBuilder(args);

builder.Services.TryAddLifecycleHook<TestResourceLifecycleHook>();
builder.Services.TryAddEventingSubscriber<TestResourceLifecycle>();

AddTestResource("healthy", HealthStatus.Healthy, "I'm fine, thanks for asking.");
AddTestResource("unhealthy", HealthStatus.Unhealthy, "I can't do that, Dave.", exceptionMessage: "Feeling unhealthy.");
Expand Down Expand Up @@ -60,11 +61,11 @@ void AddTestResource(string name, HealthStatus status, string? description = nul

internal sealed class TestResource(string name) : Resource(name);

internal sealed class TestResourceLifecycleHook(ResourceNotificationService notificationService) : IDistributedApplicationLifecycleHook
internal sealed class TestResourceLifecycle(ResourceNotificationService notificationService) : IDistributedApplicationEventingSubscriber
{
public Task BeforeStartAsync(DistributedApplicationModel appModel, CancellationToken cancellationToken)
public Task OnBeforeStartAsync(BeforeStartEvent @event, CancellationToken cancellationToken)
{
foreach (var resource in appModel.Resources.OfType<TestResource>())
foreach (var resource in @event.Model.Resources.OfType<TestResource>())
{
Task.Run(
async () =>
Expand All @@ -80,4 +81,10 @@ await notificationService.PublishUpdateAsync(

return Task.CompletedTask;
}

public Task Subscribe(IDistributedApplicationEventing eventing, DistributedApplicationExecutionContext executionContext, CancellationToken cancellationToken)
{
eventing.Subscribe<BeforeStartEvent>(OnBeforeStartAsync);
return Task.CompletedTask;
}
}
18 changes: 14 additions & 4 deletions playground/Stress/Stress.AppHost/TestResource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@

using System.Globalization;
using Aspire.Dashboard.Model;
using Aspire.Hosting.Eventing;
using Aspire.Hosting.Lifecycle;
using Microsoft.Extensions.Logging;

static class TestResourceExtensions
{
public static IResourceBuilder<TestResource> AddTestResource(this IDistributedApplicationBuilder builder, string name)
{
builder.Services.TryAddLifecycleHook<TestResourceLifecycleHook>();
builder.Services.TryAddEventingSubscriber<TestResourceLifecycle>();

var rb = builder.AddResource(new TestResource(name))
.WithInitialState(new()
Expand Down Expand Up @@ -46,13 +47,16 @@ public static IResourceBuilder<TestNestedResource> AddNestedResource(this IDistr
}
}

internal sealed class TestResourceLifecycleHook(ResourceNotificationService notificationService, ResourceLoggerService loggerService) : IDistributedApplicationLifecycleHook, IAsyncDisposable
internal sealed class TestResourceLifecycle(
ResourceNotificationService notificationService,
ResourceLoggerService loggerService
) : IDistributedApplicationEventingSubscriber, IAsyncDisposable
{
private readonly CancellationTokenSource _tokenSource = new();

public Task BeforeStartAsync(DistributedApplicationModel appModel, CancellationToken cancellationToken = default)
public Task OnBeforeStartAsync(BeforeStartEvent @event, CancellationToken cancellationToken = default)
{
foreach (var resource in appModel.Resources.OfType<TestResource>())
foreach (var resource in @event.Model.Resources.OfType<TestResource>())
{
var states = new[] { "Starting", "Running", "Finished" };

Expand Down Expand Up @@ -94,6 +98,12 @@ public ValueTask DisposeAsync()
_tokenSource.Cancel();
return default;
}

public Task Subscribe(IDistributedApplicationEventing eventing, DistributedApplicationExecutionContext executionContext, CancellationToken cancellationToken)
{
eventing.Subscribe<BeforeStartEvent>(OnBeforeStartAsync);
return Task.CompletedTask;
}
}

sealed class TestResource(string name) : Resource(name)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ internal static IDistributedApplicationBuilder AddAzureContainerAppsInfrastructu
// so Azure resources don't need to add the default role assignments themselves
builder.Services.Configure<AzureProvisioningOptions>(o => o.SupportsTargetedRoleAssignments = true);

builder.Services.TryAddLifecycleHook<AzureContainerAppsInfrastructure>();
builder.Services.TryAddEventingSubscriber<AzureContainerAppsInfrastructure>();

return builder;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

using Aspire.Hosting.ApplicationModel;
using Aspire.Hosting.Azure.AppContainers;
using Aspire.Hosting.Eventing;
using Aspire.Hosting.Lifecycle;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
Expand All @@ -13,25 +14,19 @@ namespace Aspire.Hosting.Azure;

/// <summary>
/// Represents the infrastructure for Azure Container Apps within the Aspire Hosting environment.
/// Implements the <see cref="IDistributedApplicationLifecycleHook"/> interface to provide lifecycle hooks for distributed applications.
/// </summary>
internal sealed class AzureContainerAppsInfrastructure(
ILogger<AzureContainerAppsInfrastructure> logger,
IOptions<AzureProvisioningOptions> provisioningOptions,
DistributedApplicationExecutionContext executionContext) : IDistributedApplicationLifecycleHook
DistributedApplicationExecutionContext executionContext,
IOptions<AzureProvisioningOptions> options) : IDistributedApplicationEventingSubscriber
{
public async Task BeforeStartAsync(DistributedApplicationModel appModel, CancellationToken cancellationToken = default)
public async Task OnBeforeStartAsync(BeforeStartEvent @event, CancellationToken cancellationToken = default)
{
if (executionContext.IsRunMode)
{
return;
}

var caes = appModel.Resources.OfType<AzureContainerAppEnvironmentResource>().ToArray();
var caes = @event.Model.Resources.OfType<AzureContainerAppEnvironmentResource>().ToArray();

if (caes.Length == 0)
{
EnsureNoPublishAsAcaAnnotations(appModel);
EnsureNoPublishAsAcaAnnotations(@event.Model);
return;
}

Expand All @@ -42,9 +37,9 @@ public async Task BeforeStartAsync(DistributedApplicationModel appModel, Cancell
executionContext,
environment);

foreach (var r in appModel.GetComputeResources())
foreach (var r in @event.Model.GetComputeResources())
{
var containerApp = await containerAppEnvironmentContext.CreateContainerAppAsync(r, provisioningOptions.Value, cancellationToken).ConfigureAwait(false);
var containerApp = await containerAppEnvironmentContext.CreateContainerAppAsync(r, options.Value, cancellationToken).ConfigureAwait(false);

// Capture information about the container registry used by the
// container app environment in the deployment target information
Expand All @@ -68,4 +63,14 @@ private static void EnsureNoPublishAsAcaAnnotations(DistributedApplicationModel
}
}
}

public Task Subscribe(IDistributedApplicationEventing eventing, DistributedApplicationExecutionContext executionContext, CancellationToken cancellationToken)
{
if (!executionContext.IsRunMode)
{
eventing.Subscribe<BeforeStartEvent>(OnBeforeStartAsync);
}

return Task.CompletedTask;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ internal static IDistributedApplicationBuilder AddAzureAppServiceInfrastructureC

builder.Services.Configure<AzureProvisioningOptions>(options => options.SupportsTargetedRoleAssignments = true);

builder.Services.TryAddLifecycleHook<AzureAppServiceInfrastructure>();
builder.Services.TryAddEventingSubscriber<AzureAppServiceInfrastructure>();

return builder;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.

using Aspire.Hosting.ApplicationModel;
using Aspire.Hosting.Eventing;
using Aspire.Hosting.Lifecycle;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
Expand All @@ -11,21 +12,20 @@ namespace Aspire.Hosting.Azure.AppService;
internal sealed class AzureAppServiceInfrastructure(
ILogger<AzureAppServiceInfrastructure> logger,
IOptions<AzureProvisioningOptions> provisioningOptions,
DistributedApplicationExecutionContext executionContext) :
IDistributedApplicationLifecycleHook
DistributedApplicationExecutionContext executionContext) : IDistributedApplicationEventingSubscriber
{
public async Task BeforeStartAsync(DistributedApplicationModel appModel, CancellationToken cancellationToken = default)
public async Task OnBeforeStartAsync(BeforeStartEvent @event, CancellationToken cancellationToken = default)
{
if (!executionContext.IsPublishMode)
{
return;
}

var appServiceEnvironments = appModel.Resources.OfType<AzureAppServiceEnvironmentResource>().ToArray();
var appServiceEnvironments = @event.Model.Resources.OfType<AzureAppServiceEnvironmentResource>().ToArray();

if (appServiceEnvironments.Length == 0)
{
EnsureNoPublishAsAzureAppServiceWebsiteAnnotations(appModel);
EnsureNoPublishAsAzureAppServiceWebsiteAnnotations(@event.Model);
return;
}

Expand All @@ -36,7 +36,7 @@ public async Task BeforeStartAsync(DistributedApplicationModel appModel, Cancell
executionContext,
appServiceEnvironment);

foreach (var resource in appModel.GetComputeResources())
foreach (var resource in @event.Model.GetComputeResources())
{
// Support project resources and containers with Dockerfile
if (resource is not ProjectResource && !(resource.IsContainer() && resource.TryGetAnnotationsOfType<DockerfileBuildAnnotation>(out _)))
Expand Down Expand Up @@ -67,4 +67,10 @@ private static void EnsureNoPublishAsAzureAppServiceWebsiteAnnotations(Distribut
}
}
}

public Task Subscribe(IDistributedApplicationEventing eventing, DistributedApplicationExecutionContext executionContext, CancellationToken cancellationToken)
{
eventing.Subscribe<BeforeStartEvent>(OnBeforeStartAsync);
return Task.CompletedTask;
}
}
Loading
Loading