diff --git a/Aspire.sln b/Aspire.sln
index 6ac4b364f7..8316402667 100644
--- a/Aspire.sln
+++ b/Aspire.sln
@@ -631,6 +631,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Aspire.Hosting.Sdk.Tests",
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Aspire.RuntimeIdentifier.Tool", "src\Aspire.Hosting.Sdk\Aspire.RuntimeIdentifier.Tool\Aspire.RuntimeIdentifier.Tool.csproj", "{FF2895FC-A613-43DC-96B8-E5DFA69125CA}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Aspire.Hosting.Azure.ContainerApps", "src\Aspire.Hosting.Azure.ContainerApps\Aspire.Hosting.Azure.ContainerApps.csproj", "{21FBDB19-0B8B-4F0F-8ED6-98560AD5DDA7}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -1661,6 +1663,10 @@ Global
{FF2895FC-A613-43DC-96B8-E5DFA69125CA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FF2895FC-A613-43DC-96B8-E5DFA69125CA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FF2895FC-A613-43DC-96B8-E5DFA69125CA}.Release|Any CPU.Build.0 = Release|Any CPU
+ {21FBDB19-0B8B-4F0F-8ED6-98560AD5DDA7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {21FBDB19-0B8B-4F0F-8ED6-98560AD5DDA7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {21FBDB19-0B8B-4F0F-8ED6-98560AD5DDA7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {21FBDB19-0B8B-4F0F-8ED6-98560AD5DDA7}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -1965,6 +1971,7 @@ Global
{F21F921E-1930-4BD5-B665-5EF1B82BD4D2} = {830A89EC-4029-4753-B25A-068BAE37DEC7}
{AEF07BC6-76D8-4A45-89D5-54FC4483863F} = {4981B3A5-4AFD-4191-BF7D-8692D9783D60}
{FF2895FC-A613-43DC-96B8-E5DFA69125CA} = {F534D4F8-5E3A-42FC-BCD7-4C2D6060F9C8}
+ {21FBDB19-0B8B-4F0F-8ED6-98560AD5DDA7} = {77CFE74A-32EE-400C-8930-5025E8555256}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {6DCEDFEC-988E-4CB3-B45B-191EB5086E0C}
diff --git a/Directory.Packages.props b/Directory.Packages.props
index 62f8c693d6..41c4591ffc 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -42,6 +42,8 @@
+
+
diff --git a/src/Aspire.Hosting.Azure.ContainerApps/Aspire.Hosting.Azure.ContainerApps.csproj b/src/Aspire.Hosting.Azure.ContainerApps/Aspire.Hosting.Azure.ContainerApps.csproj
new file mode 100644
index 0000000000..7a96d285fb
--- /dev/null
+++ b/src/Aspire.Hosting.Azure.ContainerApps/Aspire.Hosting.Azure.ContainerApps.csproj
@@ -0,0 +1,21 @@
+
+
+
+ $(DefaultTargetFramework)
+ true
+ aspire hosting azure
+ Azure container apps resource types for .NET Aspire.
+ true
+ $(SharedDir)Azure_256x.png
+
+
+
+ 0
+
+
+
+
+
+
+
+
diff --git a/src/Aspire.Hosting.Azure.ContainerApps/AzureContainerAppExtensions.cs b/src/Aspire.Hosting.Azure.ContainerApps/AzureContainerAppExtensions.cs
new file mode 100644
index 0000000000..11916814a8
--- /dev/null
+++ b/src/Aspire.Hosting.Azure.ContainerApps/AzureContainerAppExtensions.cs
@@ -0,0 +1,74 @@
+#pragma warning disable AZPROVISION001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
+
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using Aspire.Hosting.ApplicationModel;
+using Aspire.Hosting.Lifecycle;
+using Azure.Provisioning.AppContainers;
+
+namespace Aspire.Hosting.Azure;
+
+///
+///
+///
+public static class AzureContainerAppExtensions
+{
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static IDistributedApplicationBuilder AddContainerAppsInfrastructure(this IDistributedApplicationBuilder builder)
+ {
+ builder.Services.TryAddLifecycleHook();
+
+ return builder;
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static IResourceBuilder PublishAsContainerApp(this IResourceBuilder project, Action configure)
+ {
+ if (!project.ApplicationBuilder.ExecutionContext.IsPublishMode)
+ {
+ return project;
+ }
+
+ project.ApplicationBuilder.AddContainerAppsInfrastructure();
+
+ project.WithAnnotation(new ContainerAppCustomizationAnnotation(configure));
+
+ return project;
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static IResourceBuilder PublishAsContainerApp(this IResourceBuilder container, Action configure) where T : ContainerResource
+ {
+ if (!container.ApplicationBuilder.ExecutionContext.IsPublishMode)
+ {
+ return container;
+ }
+
+ container.ApplicationBuilder.AddContainerAppsInfrastructure();
+
+ container.WithAnnotation(new ContainerAppCustomizationAnnotation(configure));
+
+ return container;
+ }
+}
+
+internal sealed class ContainerAppCustomizationAnnotation(Action configure) : IResourceAnnotation
+{
+ public Action Configure { get; } = configure;
+}
diff --git a/src/Aspire.Hosting.Azure.ContainerApps/AzureContanierAppsInfrastructure.cs b/src/Aspire.Hosting.Azure.ContainerApps/AzureContanierAppsInfrastructure.cs
new file mode 100644
index 0000000000..acdf21ff86
--- /dev/null
+++ b/src/Aspire.Hosting.Azure.ContainerApps/AzureContanierAppsInfrastructure.cs
@@ -0,0 +1,999 @@
+#pragma warning disable AZPROVISION001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Globalization;
+using System.Text;
+using System.Text.RegularExpressions;
+using Aspire.Hosting.ApplicationModel;
+using Aspire.Hosting.Lifecycle;
+using Azure.Provisioning;
+using Azure.Provisioning.AppContainers;
+using Azure.Provisioning.Expressions;
+using Azure.Provisioning.Resources;
+
+namespace Aspire.Hosting.Azure;
+
+// Logic to generate compute and networking infrastructure for Azure Container Apps
+// based deployments.
+internal sealed class AzureContainerAppsInfastructure(DistributedApplicationExecutionContext executionContext) : IDistributedApplicationLifecycleHook
+{
+ public async Task BeforeStartAsync(DistributedApplicationModel appModel, CancellationToken cancellationToken = default)
+ {
+ if (executionContext.IsRunMode)
+ {
+ return;
+ }
+
+ var containerAppEnviromentContext = new ContainerAppEnviromentContext(
+ AzureContainerAppsEnvironment.AZURE_CONTAINER_APPS_ENVIRONMENT_ID,
+ AzureContainerAppsEnvironment.AZURE_CONTAINER_APPS_ENVIRONMENT_DEFAULT_DOMAIN,
+ AzureContainerAppsEnvironment.AZURE_CONTAINER_REGISTRY_MANAGED_IDENTITY_ID,
+ AzureContainerAppsEnvironment.AZURE_CONTAINER_REGISTRY_ENDPOINT,
+ AzureContainerAppsEnvironment.AZURE_CONTAINER_REGISTRY_MANAGED_IDENTITY_ID,
+ AzureContainerAppsEnvironment.MANAGED_IDENTITY_CLIENT_ID);
+
+ foreach (var r in appModel.Resources)
+ {
+ if (r.TryGetLastAnnotation(out var lastAnnotation) && lastAnnotation == ManifestPublishingCallbackAnnotation.Ignore)
+ {
+ continue;
+ }
+
+ if (!r.IsContainer() && r is not ProjectResource)
+ {
+ continue;
+ }
+
+ var containerApp = await containerAppEnviromentContext.CreateContainerAppAsync(r, executionContext, cancellationToken).ConfigureAwait(false);
+
+ r.Annotations.Add(new DeploymentTargetAnnotation(containerApp));
+ }
+ }
+
+ private sealed class ContainerAppEnviromentContext(
+ IManifestExpressionProvider containerAppEnvironmentId,
+ IManifestExpressionProvider containerAppDomain,
+ IManifestExpressionProvider managedIdentityId,
+ IManifestExpressionProvider containerRegistryUrl,
+ IManifestExpressionProvider containerRegistryManagedIdentityId,
+ IManifestExpressionProvider clientId
+ )
+ {
+ private IManifestExpressionProvider ContainerAppEnvironmentId => containerAppEnvironmentId;
+ private IManifestExpressionProvider ContainerAppDomain => containerAppDomain;
+ private IManifestExpressionProvider ManagedIdentityId => managedIdentityId;
+ private IManifestExpressionProvider ContainerRegistryUrl => containerRegistryUrl;
+ private IManifestExpressionProvider ContainerRegistryManagedIdentityId => containerRegistryManagedIdentityId;
+ private IManifestExpressionProvider ClientId => clientId;
+
+ private readonly Dictionary _containerApps = [];
+
+ public async Task CreateContainerAppAsync(IResource resource, DistributedApplicationExecutionContext executionContext, CancellationToken cancellationToken)
+ {
+ var context = await ProcessResourceAsync(resource, executionContext, cancellationToken).ConfigureAwait(false);
+
+ var construct = new AzureConstructResource(resource.Name, context.BuildContainerApp);
+
+ construct.Annotations.Add(new ManifestPublishingCallbackAnnotation(construct.WriteToManifest));
+
+ return construct;
+ }
+
+ private async Task ProcessResourceAsync(IResource resource, DistributedApplicationExecutionContext executionContext, CancellationToken cancellationToken)
+ {
+ if (!_containerApps.TryGetValue(resource, out var context))
+ {
+ _containerApps[resource] = context = new ContainerAppContext(resource, this);
+ await context.ProcessResourceAsync(executionContext, cancellationToken).ConfigureAwait(false);
+ }
+
+ return context;
+ }
+
+ private sealed class ContainerAppContext(IResource resource, ContainerAppEnviromentContext containerAppEnviromentContext)
+ {
+ private readonly Dictionary