Created
August 12, 2025 12:21
-
-
Save davidfowl/12adb8ae6c44e0df924476e8e966b5bf to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Microsoft.Extensions.DependencyInjection; | |
using Microsoft.Extensions.Hosting; | |
using Microsoft.Extensions.Logging; | |
using System.IO; | |
namespace Aspire.Hosting; | |
public static class DevCertHostingExtensions | |
{ | |
/// <summary> | |
/// Injects the ASP.NET Core HTTPS developer certificate into the resource via the specified environment variables when | |
/// <paramref name="builder"/>.<see cref="IResourceBuilder{T}.ApplicationBuilder">ApplicationBuilder</see>.<see cref="IDistributedApplicationBuilder.ExecutionContext">ExecutionContext</see>.<see cref="DistributedApplicationExecutionContext.IsRunMode">IsRunMode</see><c> == true</c>.<br/> | |
/// If the resource is a <see cref="ContainerResource"/>, the certificate files will be provided via WithContainerFiles. | |
/// </summary> | |
/// <remarks> | |
/// This method <strong>does not</strong> configure an HTTPS endpoint on the resource. | |
/// Use <see cref="ResourceBuilderExtensions.WithHttpsEndpoint{TResource}"/> to configure an HTTPS endpoint. | |
/// </remarks> | |
public static IResourceBuilder<TResource> RunWithHttpsDevCertificate<TResource>( | |
this IResourceBuilder<TResource> builder, string certFileEnv, string certKeyFileEnv) | |
where TResource : IResourceWithEnvironment, IResourceWithWaitSupport | |
{ | |
if (!builder.ApplicationBuilder.ExecutionContext.IsRunMode) | |
{ | |
return builder; | |
} | |
// Create temp directory for certificate export | |
var tempDir = Directory.CreateTempSubdirectory("aspire-dev-certs"); | |
var certExportPath = Path.Combine(tempDir.FullName, "dev-cert.pem"); | |
var certKeyExportPath = Path.Combine(tempDir.FullName, "dev-cert.key"); | |
// Create a unique resource name for the certificate export | |
var exportResourceName = $"dev-cert-export"; | |
// Check if we already have a certificate export resource | |
var existingResource = builder.ApplicationBuilder.Resources.FirstOrDefault(r => r.Name == exportResourceName); | |
IResourceBuilder<ExecutableResource> exportExecutable; | |
if (existingResource == null) | |
{ | |
// Create the executable resource to export the certificate | |
exportExecutable = builder.ApplicationBuilder | |
.AddExecutable(exportResourceName, "dotnet", tempDir.FullName) | |
.WithEnvironment("DOTNET_CLI_UI_LANGUAGE", "en") // Ensure consistent output language | |
.WithArgs(context => | |
{ | |
context.Args.Add("dev-certs"); | |
context.Args.Add("https"); | |
context.Args.Add("--export-path"); | |
context.Args.Add(certExportPath); | |
context.Args.Add("--format"); | |
context.Args.Add("Pem"); | |
context.Args.Add("--no-password"); | |
}); | |
} | |
else | |
{ | |
exportExecutable = builder.ApplicationBuilder.CreateResourceBuilder((ExecutableResource)existingResource); | |
} | |
builder.WaitForCompletion(exportExecutable); | |
// Configure the current resource with the certificate paths | |
if (builder.Resource is ContainerResource containerResource) | |
{ | |
// Use WithContainerFiles to provide the certificate files to the container | |
const string DEV_CERT_BIND_MOUNT_DEST_DIR = "/dev-certs"; | |
const string CERT_FILE_NAME = "dev-cert.pem"; | |
const string CERT_KEY_FILE_NAME = "dev-cert.key"; | |
var certFileDest = $"{DEV_CERT_BIND_MOUNT_DEST_DIR}/{CERT_FILE_NAME}"; | |
var certKeyFileDest = $"{DEV_CERT_BIND_MOUNT_DEST_DIR}/{CERT_KEY_FILE_NAME}"; | |
builder.ApplicationBuilder.CreateResourceBuilder(containerResource) | |
.WithContainerFiles(DEV_CERT_BIND_MOUNT_DEST_DIR, (context, cancellationToken) => | |
{ | |
var files = new List<ContainerFile>(); | |
// Check if certificate files exist before adding them | |
if (File.Exists(certExportPath)) | |
{ | |
files.Add(new ContainerFile | |
{ | |
Name = CERT_FILE_NAME, | |
SourcePath = certExportPath | |
}); | |
} | |
if (File.Exists(certKeyExportPath)) | |
{ | |
files.Add(new ContainerFile | |
{ | |
Name = CERT_KEY_FILE_NAME, | |
SourcePath = certKeyExportPath | |
}); | |
} | |
return Task.FromResult(files.AsEnumerable<ContainerFileSystemItem>()); | |
}) | |
.WithEnvironment(certFileEnv, certFileDest) | |
.WithEnvironment(certKeyFileEnv, certKeyFileDest); | |
} | |
else | |
{ | |
// For non-container resources, set the file paths directly | |
builder | |
.WithEnvironment(certFileEnv, certExportPath) | |
.WithEnvironment(certKeyFileEnv, certKeyExportPath); | |
} | |
return builder; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment