File: ContainerRegistryResourceBuilderExtensions.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;
using Aspire.Hosting.ApplicationModel;
 
namespace Aspire.Hosting;
 
/// <summary>
/// Provides extension methods for adding container registry resources to the distributed application.
/// </summary>
public static class ContainerRegistryResourceBuilderExtensions
{
    /// <summary>
    /// Adds a container registry resource to the application model with parameterized values.
    /// </summary>
    /// <param name="builder">The distributed application builder.</param>
    /// <param name="name">The name of the container registry resource.</param>
    /// <param name="endpoint">An <see cref="IResourceBuilder{ParameterResource}"/> containing the registry endpoint URL or hostname.</param>
    /// <param name="repository">An optional <see cref="IResourceBuilder{ParameterResource}"/> containing the repository path within the registry.</param>
    /// <returns>An <see cref="IResourceBuilder{ContainerRegistryResource}"/> for the container registry resource.</returns>
    /// <remarks>
    /// Use this method when the registry endpoint and repository values need to be provided dynamically
    /// via configuration or user input. The resource is only added to the application model in publish mode;
    /// in run mode, a resource builder is created without adding the resource to the model.
    /// </remarks>
    /// <example>
    /// Add a container registry with parameterized values:
    /// <code>
    /// var endpointParameter = builder.AddParameter("registry-endpoint");
    /// var repositoryParameter = builder.AddParameter("registry-repo");
    /// var registry = builder.AddContainerRegistry("my-registry", endpointParameter, repositoryParameter);
    /// </code>
    /// </example>
    [Experimental("ASPIRECOMPUTE003", UrlFormat = "https://aka.ms/aspire/diagnostics/{0}")]
    public static IResourceBuilder<ContainerRegistryResource> AddContainerRegistry(
        this IDistributedApplicationBuilder builder,
        [ResourceName] string name,
        IResourceBuilder<ParameterResource> endpoint,
        IResourceBuilder<ParameterResource>? repository = null)
    {
        ArgumentNullException.ThrowIfNull(builder);
        ArgumentException.ThrowIfNullOrEmpty(name);
        ArgumentNullException.ThrowIfNull(endpoint);
 
        var endpointExpression = ReferenceExpression.Create($"{endpoint.Resource}");
        var repositoryExpression = repository is not null
            ? ReferenceExpression.Create($"{repository.Resource}")
            : null;
 
        var resource = new ContainerRegistryResource(name, endpointExpression, repositoryExpression);
 
        return builder.ExecutionContext.IsRunMode
            ? builder.CreateResourceBuilder(resource)
            : builder.AddResource(resource);
    }
 
    /// <summary>
    /// Adds a container registry resource to the application model with literal string values.
    /// </summary>
    /// <param name="builder">The distributed application builder.</param>
    /// <param name="name">The name of the container registry resource.</param>
    /// <param name="endpoint">The registry endpoint URL or hostname (e.g., "docker.io", "ghcr.io").</param>
    /// <param name="repository">The optional repository path within the registry (e.g., "myusername" for Docker Hub, "owner/repo" for GHCR).</param>
    /// <returns>An <see cref="IResourceBuilder{ContainerRegistryResource}"/> for the container registry resource.</returns>
    /// <remarks>
    /// Use this method when the registry endpoint and repository values are known at design time
    /// and do not need to be parameterized. The resource is only added to the application model in publish mode;
    /// in run mode, a resource builder is created without adding the resource to the model.
    /// </remarks>
    /// <example>
    /// Add a Docker Hub container registry:
    /// <code>
    /// var registry = builder.AddContainerRegistry("docker-hub", "docker.io", "myusername");
    /// </code>
    /// </example>
    /// <example>
    /// Add a GitHub Container Registry:
    /// <code>
    /// var registry = builder.AddContainerRegistry("ghcr", "ghcr.io", "owner/repo");
    /// </code>
    /// </example>
    [Experimental("ASPIRECOMPUTE003", UrlFormat = "https://aka.ms/aspire/diagnostics/{0}")]
    public static IResourceBuilder<ContainerRegistryResource> AddContainerRegistry(
        this IDistributedApplicationBuilder builder,
        [ResourceName] string name,
        string endpoint,
        string? repository = null)
    {
        ArgumentNullException.ThrowIfNull(builder);
        ArgumentException.ThrowIfNullOrEmpty(name);
        ArgumentException.ThrowIfNullOrEmpty(endpoint);
 
        var endpointExpression = ReferenceExpression.Create($"{endpoint}");
        var repositoryExpression = repository is not null
            ? ReferenceExpression.Create($"{repository}")
            : null;
 
        var resource = new ContainerRegistryResource(name, endpointExpression, repositoryExpression);
 
        return builder.ExecutionContext.IsRunMode
            ? builder.CreateResourceBuilder(resource)
            : builder.AddResource(resource);
    }
 
    /// <summary>
    /// Configures the resource to use the specified container registry for container image operations.
    /// </summary>
    /// <typeparam name="TDestination">The type of the destination resource.</typeparam>
    /// <typeparam name="TContainerRegistry">The type of the container registry resource.</typeparam>
    /// <param name="builder">The resource builder.</param>
    /// <param name="registry">The container registry resource builder.</param>
    /// <returns>The resource builder for chaining.</returns>
    /// <remarks>
    /// This method adds a <see cref="ContainerRegistryReferenceAnnotation"/> to the resource,
    /// indicating that the resource should use the specified container registry for container image operations.
    /// </remarks>
    /// <example>
    /// Configure a project to use a container registry:
    /// <code>
    /// var registry = builder.AddContainerRegistry("docker-hub", "docker.io", "myusername");
    /// var project = builder.AddProject&lt;MyProject&gt;("myproject")
    ///     .WithContainerRegistry(registry);
    /// </code>
    /// </example>
    [Experimental("ASPIRECOMPUTE003", UrlFormat = "https://aka.ms/aspire/diagnostics/{0}")]
    public static IResourceBuilder<TDestination> WithContainerRegistry<TDestination, TContainerRegistry>(
        this IResourceBuilder<TDestination> builder,
        IResourceBuilder<TContainerRegistry> registry)
        where TDestination : IResource
        where TContainerRegistry : IResource, IContainerRegistry
    {
        ArgumentNullException.ThrowIfNull(builder);
        ArgumentNullException.ThrowIfNull(registry);
 
        return builder.WithAnnotation(new ContainerRegistryReferenceAnnotation(registry.Resource));
    }
}