File: Lifecycle\RequiredCommandValidationLifecycleHook.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.
 
#pragma warning disable ASPIRECOMMAND001
 
using Aspire.Hosting.ApplicationModel;
using Aspire.Hosting.Eventing;
 
namespace Aspire.Hosting.Lifecycle;
 
/// <summary>
/// An eventing subscriber that validates required commands are installed before resources start.
/// </summary>
/// <remarks>
/// This subscriber processes <see cref="RequiredCommandAnnotation"/> on resources and delegates
/// validation to <see cref="IRequiredCommandValidator"/>.
/// </remarks>
internal sealed class RequiredCommandValidationLifecycleHook(
    IRequiredCommandValidator validator) : IDistributedApplicationEventingSubscriber
{
    private readonly IRequiredCommandValidator _validator = validator ?? throw new ArgumentNullException(nameof(validator));
 
    /// <inheritdoc />
    public Task SubscribeAsync(IDistributedApplicationEventing eventing, DistributedApplicationExecutionContext executionContext, CancellationToken cancellationToken)
    {
        // Subscribe to BeforeResourceStartedEvent to validate commands before each resource starts
        eventing.Subscribe<BeforeResourceStartedEvent>(ValidateRequiredCommandsAsync);
        return Task.CompletedTask;
    }
 
    private async Task ValidateRequiredCommandsAsync(BeforeResourceStartedEvent @event, CancellationToken cancellationToken)
    {
        var resource = @event.Resource;
 
        // Get all RequiredCommandAnnotation instances on the resource
        var requiredCommands = resource.Annotations.OfType<RequiredCommandAnnotation>().ToList();
 
        if (requiredCommands.Count == 0)
        {
            return;
        }
 
        foreach (var annotation in requiredCommands)
        {
            await _validator.ValidateAsync(resource, annotation, cancellationToken).ConfigureAwait(false);
        }
    }
}