| File: Pipelines\DistributedApplicationPipelineExtensions.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 System.Diagnostics.CodeAnalysis; namespace Aspire.Hosting.Pipelines; /// <summary> /// Extension methods for <see cref="IDistributedApplicationPipeline"/>. /// </summary> [Experimental("ASPIREPIPELINES001", UrlFormat = "https://aka.ms/aspire/diagnostics/{0}")] public static class DistributedApplicationPipelineExtensions { /// <summary> /// Configures an action that runs after the named pipeline step and all of its dependencies complete. /// </summary> /// <param name="pipeline">The distributed application pipeline.</param> /// <param name="stepName">The name of the pipeline step.</param> /// <param name="action">A final action to execute.</param> /// <returns>The distributed application pipeline for chaining.</returns> /// <exception cref="ArgumentNullException"> /// Thrown when <paramref name="pipeline"/>, <paramref name="stepName"/>, or <paramref name="action"/> is null. /// </exception> /// <exception cref="ArgumentException">Thrown when <paramref name="stepName"/> is empty.</exception> /// <exception cref="InvalidOperationException"> /// Thrown during pipeline resolution when the named step does not exist. /// </exception> /// <remarks> /// The final action is configured when the pipeline graph is resolved, so it runs after dependencies /// added by resource annotations and other pipeline configuration callbacks. Multiple final actions /// for the same step execute sequentially in registration order. If a final action fails, subsequent /// final actions are not invoked. /// </remarks> [AspireExportIgnore(Reason = "Delegate callbacks are not ATS-compatible.")] public static IDistributedApplicationPipeline WithFinalAction( this IDistributedApplicationPipeline pipeline, string stepName, Func<PipelineStepContext, Task> action) { ArgumentNullException.ThrowIfNull(pipeline); ArgumentException.ThrowIfNullOrEmpty(stepName); ArgumentNullException.ThrowIfNull(action); pipeline.AddPipelineConfiguration(context => { var step = context.Steps.FirstOrDefault(candidate => candidate.Name == stepName); if (step is null) { var availableSteps = string.Join(", ", context.Steps.Select(candidate => $"'{candidate.Name}'")); throw new InvalidOperationException( $"Step '{stepName}' not found in pipeline. Available steps: {availableSteps}"); } step.AddFinalAction(action); return Task.CompletedTask; }); return pipeline; } /// <summary> /// Disables the publish and deploy validation that requires build-only containers to be consumed by another resource. /// </summary> /// <param name="pipeline">The distributed application pipeline.</param> /// <returns>The distributed application pipeline for chaining.</returns> /// <remarks> /// This is an application-wide escape hatch for scenarios where the build-only container validation is too restrictive /// for a particular app. Prefer wiring build-only containers through <c>PublishWithContainerFiles</c> or /// <c>PublishWithStaticFiles</c> when possible. /// </remarks> [AspireExport] public static IDistributedApplicationPipeline DisableBuildOnlyContainerValidation(this IDistributedApplicationPipeline pipeline) { ArgumentNullException.ThrowIfNull(pipeline); pipeline.AddPipelineConfiguration(static context => { var validationStep = context.Steps.FirstOrDefault(step => step.Name == DistributedApplicationPipeline.ValidateBuildOnlyContainerReferencesStepName); validationStep?.RequiredBySteps.Clear(); return Task.CompletedTask; }); return pipeline; } }