Skip to content

Document the updated behavior of ResourceContainerImageBuilder #4137

@captainsafia

Description

@captainsafia

Location in table of contents.

Fundamentals > Publishing and Deployment > Building container images

Reason for the article

Recent changes in .NET Aspire 9.4 expanded support for the ResourceContainerImageBuilder API that is useful in publish scenarios.

  • Added strongly-typed ContainerBuildOptions so callers can pass extra MSBuild properties (output path, image format, target platform) to the underlying dotnet publish /t:PublishContainer invocation.
  • Made the container-runtime health check run only when at least one resource needs a Dockerfile build, avoiding false-positive errors in projects that publish straight from .NET assemblies.

Article abstract

ResourceContainerImageBuilder is the service in the Aspire.Hosting.Publishing layer that turns a resource definition into a runnable container image for local development or deployment. It inspects each resource in the distributed-application model and decides whether the image can be reused, must be built with dotnet publish /t:PublishContainer (for project resources), or needs a Dockerfile build via the local container runtime. Callers can supply an optional ContainerBuildOptions object to control the image format (Docker vs OCI), target platform, output path, additional MSBuild properties, and build arguments, giving fine-grained control over the artifacts produced. The builder now performs a runtime-health probe only when at least one Dockerfile-backed resource is present, avoiding spurious errors in projects that publish directly from assemblies; if the runtime is required but unhealthy, it throws an explicit InvalidOperationException to surface the problem early. Throughout the process it emits structured progress events (via PublishingActivityReporter) so CLI commands can show real-time status.

The following code snippet demonstrates how the ResourceContainerImageBuilder can be used in a custom publisher to generate Linux x64 OCI images that are published to an output directory. The key takeaway is that image construction now lives inside your resource’s publish phase, driven by first-class API support rather than ad-hoc shell commands.

  • Attach a PublishingCallbackAnnotation to your custom resource.
  • Resolve ResourceContainerImageBuilder from the callback’s PublishingContext.Services and call either BuildImageAsync (single resource) or BuildImagesAsync (multiple compute resources).
  • Pass a ContainerBuildOptions instance to control ImageFormat, TargetPlatform, output folder, extra MSBuild properties, and build args.
  • Rely on the builder’s conditional health-check: it pings Docker/Podman only when a Dockerfile build is needed and throws InvalidOperationException if the runtime is missing or unhealthy, making failures visible early.
using Aspire.Hosting.ApplicationModel;
using Aspire.Hosting.Publishing;
using Microsoft.Extensions.DependencyInjection;
using System.IO;
using System.Linq;
using System.Threading.Tasks;

[Experimental("ASPIRECOMPUTE001")]
public sealed class ComputeEnvironmentResource : Resource
{
    public ComputeEnvironmentResource(string name) : base(name)
    {
        // Register a publishing callback that will build images.
        Annotations.Add(new PublishingCallbackAnnotation(PublishAsync));
    }

    private async Task PublishAsync(PublishingContext context)
    {
        // 1. Get the shared image builder from DI
        var imageBuilder =
            context.Services.GetRequiredService<ResourceContainerImageBuilder>();

        // 2. Collect all compute resources that need images
        var computeResources = context.Model.Resources
                                      .OfType<IResource>() // include ProjectResource, DockerfileResource, etc.
                                      .Where(r => r.HasAnnotation<ContainerImageAnnotation>())
                                      .ToList();

        // 3. Describe how you want the images produced
        var opts = new ContainerBuildOptions
        {
            ImageFormat    = ContainerImageFormat.Oci,
            TargetPlatform = ContainerTargetPlatform.LinuxAmd64,
            OutputPath     = Path.Combine(context.OutputPath, "images")
        };

        // 4. Kick off the build; fails fast if the container runtime is unhealthy
        await imageBuilder.BuildImagesAsync(
            computeResources, opts, context.CancellationToken);
    }
}

Relevant searches

  • "ResourceContainerImageBuilder ContainerBuildOptions"

Associated WorkItem - 474249

Metadata

Metadata

Assignees

Labels

📌 seQUESTeredIdentifies that an issue has been imported into Quest.area-docs

Projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions