File: Ats\NotificationExports.cs
Web Access
Project: src\src\Aspire.Hosting\Aspire.Hosting.csproj (Aspire.Hosting)
// 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.ApplicationModel;
 
namespace Aspire.Hosting.Ats;
 
/// <summary>
/// ATS exports for resource notification operations.
/// </summary>
internal static class NotificationExports
{
    /// <summary>
    /// Waits for a resource to reach a specified state.
    /// </summary>
    [AspireExport("waitForResourceState", Description = "Waits for a resource to reach a specified state")]
    public static Task WaitForResourceState(
        ResourceNotificationService notificationService,
        string resourceName,
        string? targetState = null)
    {
        return notificationService.WaitForResourceAsync(resourceName, targetState);
    }
 
    /// <summary>
    /// Waits for a resource to reach one of the specified states.
    /// </summary>
    [AspireExport("waitForResourceStates", Description = "Waits for a resource to reach one of the specified states")]
    public static Task<string> WaitForResourceStates(
        ResourceNotificationService notificationService,
        string resourceName,
        string[] targetStates)
    {
        return notificationService.WaitForResourceAsync(resourceName, targetStates);
    }
 
    /// <summary>
    /// Waits for a resource to become healthy.
    /// </summary>
    [AspireExport("waitForResourceHealthy", Description = "Waits for a resource to become healthy")]
    public static async Task<ResourceEventDto> WaitForResourceHealthy(
        ResourceNotificationService notificationService,
        string resourceName)
    {
        var resourceEvent = await notificationService.WaitForResourceHealthyAsync(resourceName).ConfigureAwait(false);
        return ResourceEventDto.FromResourceEvent(resourceEvent);
    }
 
    /// <summary>
    /// Waits for all dependencies of a resource to be ready.
    /// </summary>
    [AspireExport("waitForDependencies", Description = "Waits for all dependencies of a resource to be ready")]
    public static Task WaitForDependencies(
        ResourceNotificationService notificationService,
        IResourceBuilder<IResource> resource)
    {
        return notificationService.WaitForDependenciesAsync(resource.Resource, CancellationToken.None);
    }
 
    /// <summary>
    /// Tries to get the current state of a resource.
    /// </summary>
    [AspireExport("tryGetResourceState", Description = "Tries to get the current state of a resource")]
    public static ResourceEventDto? TryGetResourceState(
        ResourceNotificationService notificationService,
        string resourceName)
    {
        if (notificationService.TryGetCurrentState(resourceName, out var resourceEvent))
        {
            return ResourceEventDto.FromResourceEvent(resourceEvent);
        }
        return null;
    }
 
    /// <summary>
    /// Publishes an update for a resource's state.
    /// </summary>
    [AspireExport("publishResourceUpdate", Description = "Publishes an update for a resource's state")]
    public static Task PublishResourceUpdate(
        ResourceNotificationService notificationService,
        IResourceBuilder<IResource> resource,
        string? state = null,
        string? stateStyle = null)
    {
        return notificationService.PublishUpdateAsync(resource.Resource, snapshot =>
        {
            if (state != null)
            {
                snapshot = snapshot with { State = new ResourceStateSnapshot(state, stateStyle) };
            }
            return snapshot;
        });
    }
}
 
/// <summary>
/// DTO for resource events returned from notification service.
/// </summary>
[AspireDto]
internal sealed class ResourceEventDto
{
    /// <summary>
    /// The resource name.
    /// </summary>
    public required string ResourceName { get; init; }
 
    /// <summary>
    /// The unique resource ID.
    /// </summary>
    public required string ResourceId { get; init; }
 
    /// <summary>
    /// The current state text.
    /// </summary>
    public string? State { get; init; }
 
    /// <summary>
    /// The state style (e.g., "success", "warn", "error").
    /// </summary>
    public string? StateStyle { get; init; }
 
    /// <summary>
    /// The health status of the resource.
    /// </summary>
    public string? HealthStatus { get; init; }
 
    /// <summary>
    /// The exit code if the resource has exited.
    /// </summary>
    public int? ExitCode { get; init; }
 
    /// <summary>
    /// Creates a DTO from a ResourceEvent.
    /// </summary>
    internal static ResourceEventDto FromResourceEvent(ResourceEvent resourceEvent)
    {
        return new ResourceEventDto
        {
            ResourceName = resourceEvent.Resource.Name,
            ResourceId = resourceEvent.ResourceId,
            State = resourceEvent.Snapshot.State?.Text,
            StateStyle = resourceEvent.Snapshot.State?.Style,
            HealthStatus = resourceEvent.Snapshot.HealthStatus?.ToString(),
            ExitCode = resourceEvent.Snapshot.ExitCode
        };
    }
}