diff --git a/Directory.Packages.props b/Directory.Packages.props
index 93e12965cf..4b9bda200f 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -25,7 +25,7 @@
-
+
diff --git a/playground/cdk/CdkSample.ApiService/CdkSample.ApiService.csproj b/playground/cdk/CdkSample.ApiService/CdkSample.ApiService.csproj
index e458308746..493052dc3b 100644
--- a/playground/cdk/CdkSample.ApiService/CdkSample.ApiService.csproj
+++ b/playground/cdk/CdkSample.ApiService/CdkSample.ApiService.csproj
@@ -10,6 +10,7 @@
+
diff --git a/playground/cdk/CdkSample.ApiService/Program.cs b/playground/cdk/CdkSample.ApiService/Program.cs
index 23cd8a93ac..655fb82046 100644
--- a/playground/cdk/CdkSample.ApiService/Program.cs
+++ b/playground/cdk/CdkSample.ApiService/Program.cs
@@ -15,17 +15,19 @@
builder.AddSqlServerDbContext("sqldb");
builder.AddAzureKeyVaultClient("mykv");
builder.AddRedisClient("cache");
+builder.AddNpgsqlDbContext("pgsqldb");
var app = builder.Build();
-app.MapGet("/", async (BlobServiceClient bsc, SqlContext context, SecretClient sc, IConnectionMultiplexer connection) =>
+app.MapGet("/", async (BlobServiceClient bsc, SqlContext sqlContext, SecretClient sc, IConnectionMultiplexer connection, NpgsqlContext npgsqlContext) =>
{
return new
{
redisEntries = await TestRedisAsync(connection),
secretChecked = await TestSecretAsync(sc),
blobFiles = await TestBlobStorageAsync(bsc),
- sqlRows = await TestSqlServerAsync(context)
+ sqlRows = await TestSqlServerAsync(sqlContext),
+ npgsqlRows = await TestNpgsqlAsync(npgsqlContext),
};
});
app.Run();
@@ -89,10 +91,28 @@ static async Task> TestSqlServerAsync(SqlContext context)
return entries;
}
+static async Task> TestNpgsqlAsync(NpgsqlContext context)
+{
+ await context.Database.EnsureCreatedAsync();
+
+ var entry = new Entry();
+ await context.Entries.AddAsync(entry);
+ await context.SaveChangesAsync();
+
+ var entries = await context.Entries.ToListAsync();
+ return entries;
+}
+
+public class NpgsqlContext(DbContextOptions options) : DbContext(options)
+{
+ public DbSet Entries { get; set; }
+}
+
public class SqlContext(DbContextOptions options) : DbContext(options)
{
public DbSet Entries { get; set; }
}
+
public class Entry
{
public Guid Id { get; set; } = Guid.NewGuid();
diff --git a/playground/cdk/CdkSample.AppHost/Program.cs b/playground/cdk/CdkSample.AppHost/Program.cs
index 4ba95fd325..89252acb28 100644
--- a/playground/cdk/CdkSample.AppHost/Program.cs
+++ b/playground/cdk/CdkSample.AppHost/Program.cs
@@ -28,11 +28,20 @@
var cache = builder.AddRedis("cache").AsAzureRedisConstruct();
+var pgsqlAdministratorLogin = builder.AddParameter("pgsqlAdministratorLogin");
+var pgsqlAdministratorLoginPassword = builder.AddParameter("pgsqlAdministratorLoginPassword", secret: true);
+var pgsqldb = builder.AddPostgres("pgsql")
+ .AsAzurePostgresFlexibleServerConstruct(pgsqlAdministratorLogin, pgsqlAdministratorLoginPassword)
+ .AddDatabase("pgsqldb");
+
+var pgsql2 = builder.AddPostgres("pgsql2").AsAzurePostgresFlexibleServerConstruct();
+
builder.AddProject("api")
.WithReference(blobs)
.WithReference(sqldb)
.WithReference(keyvault)
- .WithReference(cache);
+ .WithReference(cache)
+ .WithReference(pgsqldb);
// This project is only added in playground projects to support development/debugging
// of the dashboard. It is not required in end developer code. Comment out this code
diff --git a/playground/cdk/CdkSample.AppHost/aspire-manifest.json b/playground/cdk/CdkSample.AppHost/aspire-manifest.json
index 53f854fd7c..ea57b86c65 100644
--- a/playground/cdk/CdkSample.AppHost/aspire-manifest.json
+++ b/playground/cdk/CdkSample.AppHost/aspire-manifest.json
@@ -48,6 +48,17 @@
"params": {
"principalId": "",
"principalName": ""
+ },
+ "inputs": {
+ "password": {
+ "type": "string",
+ "secret": true,
+ "default": {
+ "generate": {
+ "minLength": 10
+ }
+ }
+ }
}
},
"sqldb": {
@@ -73,6 +84,81 @@
"keyVaultName": ""
}
},
+ "pgsqlAdministratorLogin": {
+ "type": "parameter.v0",
+ "value": "{pgsqlAdministratorLogin.inputs.value}",
+ "inputs": {
+ "value": {
+ "type": "string"
+ }
+ }
+ },
+ "pgsqlAdministratorLoginPassword": {
+ "type": "parameter.v0",
+ "value": "{pgsqlAdministratorLoginPassword.inputs.value}",
+ "inputs": {
+ "value": {
+ "type": "string",
+ "secret": true
+ }
+ }
+ },
+ "pgsql": {
+ "type": "azure.bicep.v0",
+ "connectionString": "{pgsql.secretOutputs.connectionString}",
+ "path": "pgsql.module.bicep",
+ "params": {
+ "principalId": "",
+ "keyVaultName": "",
+ "administratorLogin": "{pgsqlAdministratorLogin.value}",
+ "administratorLoginPassword": "{pgsqlAdministratorLoginPassword.value}"
+ },
+ "inputs": {
+ "password": {
+ "type": "string",
+ "secret": true,
+ "default": {
+ "generate": {
+ "minLength": 10
+ }
+ }
+ }
+ }
+ },
+ "pgsqldb": {
+ "type": "value.v0",
+ "connectionString": "{pgsql.connectionString};Database=pgsqldb"
+ },
+ "pgsql2": {
+ "type": "azure.bicep.v0",
+ "connectionString": "{pgsql2.secretOutputs.connectionString}",
+ "path": "pgsql2.module.bicep",
+ "params": {
+ "principalId": "",
+ "keyVaultName": "",
+ "administratorLogin": "{pgsql2.inputs.username}",
+ "administratorLoginPassword": "{pgsql2.inputs.password}"
+ },
+ "inputs": {
+ "password": {
+ "type": "string",
+ "secret": true,
+ "default": {
+ "generate": {
+ "minLength": 10
+ }
+ }
+ },
+ "username": {
+ "type": "string",
+ "default": {
+ "generate": {
+ "minLength": 10
+ }
+ }
+ }
+ }
+ },
"api": {
"type": "project.v0",
"path": "../CdkSample.ApiService/CdkSample.ApiService.csproj",
@@ -82,7 +168,8 @@
"ConnectionStrings__blobs": "{blobs.connectionString}",
"ConnectionStrings__sqldb": "{sqldb.connectionString}",
"ConnectionStrings__mykv": "{mykv.connectionString}",
- "ConnectionStrings__cache": "{cache.connectionString}"
+ "ConnectionStrings__cache": "{cache.connectionString}",
+ "ConnectionStrings__pgsqldb": "{pgsqldb.connectionString}"
},
"bindings": {
"http": {
diff --git a/playground/cdk/CdkSample.AppHost/aspire.hosting.azure.bicep.postgres.bicep b/playground/cdk/CdkSample.AppHost/aspire.hosting.azure.bicep.postgres.bicep
new file mode 100644
index 0000000000..77c57ac31c
--- /dev/null
+++ b/playground/cdk/CdkSample.AppHost/aspire.hosting.azure.bicep.postgres.bicep
@@ -0,0 +1,68 @@
+param administratorLogin string
+param keyVaultName string
+
+@secure()
+param administratorLoginPassword string
+param location string = resourceGroup().location
+param serverName string
+param serverEdition string = 'Burstable'
+param skuSizeGB int = 32
+param dbInstanceType string = 'Standard_B1ms'
+param haMode string = 'Disabled'
+param availabilityZone string = '1'
+param version string = '16'
+param databases array = []
+
+var resourceToken = uniqueString(resourceGroup().id)
+
+resource pgserver 'Microsoft.DBforPostgreSQL/flexibleServers@2021-06-01' = {
+ name: '${serverName}-${resourceToken}'
+ location: location
+ sku: {
+ name: dbInstanceType
+ tier: serverEdition
+ }
+ properties: {
+ version: version
+ administratorLogin: administratorLogin
+ administratorLoginPassword: administratorLoginPassword
+ network: {
+ delegatedSubnetResourceId: null
+ privateDnsZoneArmResourceId: null
+ }
+ highAvailability: {
+ mode: haMode
+ }
+ storage: {
+ storageSizeGB: skuSizeGB
+ }
+ backup: {
+ backupRetentionDays: 7
+ geoRedundantBackup: 'Disabled'
+ }
+ availabilityZone: availabilityZone
+ }
+
+ resource firewallRules 'firewallRules@2021-06-01' = {
+ name: 'fw-pg-localdev'
+ properties: {
+ startIpAddress: '0.0.0.0'
+ endIpAddress: '255.255.255.255'
+ }
+ }
+
+ resource database 'databases@2021-06-01' = [for name in databases: {
+ name: name
+ }]
+}
+
+resource vault 'Microsoft.KeyVault/vaults@2023-07-01' existing = {
+ name: keyVaultName
+
+ resource secret 'secrets@2023-07-01' = {
+ name: 'connectionString'
+ properties: {
+ value: 'Host=${pgserver.properties.fullyQualifiedDomainName};Username=${administratorLogin};Password=${administratorLoginPassword}'
+ }
+ }
+}
diff --git a/playground/cdk/CdkSample.AppHost/cache.module.bicep b/playground/cdk/CdkSample.AppHost/cache.module.bicep
index 32e5fe0636..bbf78fdd25 100644
--- a/playground/cdk/CdkSample.AppHost/cache.module.bicep
+++ b/playground/cdk/CdkSample.AppHost/cache.module.bicep
@@ -1,13 +1,13 @@
targetScope = 'resourceGroup'
@description('')
-param principalId string
+param location string = resourceGroup().location
@description('')
param keyVaultName string
@description('')
-param location string = resourceGroup().location
+param principalId string
resource keyVault_IeF8jZvXV 'Microsoft.KeyVault/vaults@2023-02-01' existing = {
diff --git a/playground/cdk/CdkSample.AppHost/mykv.module.bicep b/playground/cdk/CdkSample.AppHost/mykv.module.bicep
index aff9e9c3da..ae9a8310bf 100644
--- a/playground/cdk/CdkSample.AppHost/mykv.module.bicep
+++ b/playground/cdk/CdkSample.AppHost/mykv.module.bicep
@@ -1,13 +1,13 @@
targetScope = 'resourceGroup'
@description('')
-param principalId string
+param location string = resourceGroup().location
@description('')
-param principalType string
+param principalId string
@description('')
-param location string = resourceGroup().location
+param principalType string
@description('')
param signaturesecret string
diff --git a/playground/cdk/CdkSample.AppHost/pgsql.module.bicep b/playground/cdk/CdkSample.AppHost/pgsql.module.bicep
new file mode 100644
index 0000000000..12a85ae3a7
--- /dev/null
+++ b/playground/cdk/CdkSample.AppHost/pgsql.module.bicep
@@ -0,0 +1,72 @@
+targetScope = 'resourceGroup'
+
+@description('')
+param location string = resourceGroup().location
+
+@description('')
+param administratorLogin string
+
+@secure()
+@description('')
+param administratorLoginPassword string
+
+@description('')
+param principalId string
+
+@description('')
+param keyVaultName string
+
+
+resource keyVault_IeF8jZvXV 'Microsoft.KeyVault/vaults@2023-02-01' existing = {
+ name: keyVaultName
+}
+
+resource postgreSqlFlexibleServer_UTKFzAL0U 'Microsoft.DBforPostgreSQL/flexibleServers@2022-12-01' = {
+ name: toLower(take(concat('pgsql', uniqueString(resourceGroup().id)), 24))
+ location: location
+ sku: {
+ name: 'Standard_B1ms'
+ tier: 'Burstable'
+ }
+ properties: {
+ administratorLogin: administratorLogin
+ administratorLoginPassword: administratorLoginPassword
+ version: '16'
+ storage: {
+ storageSizeGB: 32
+ }
+ backup: {
+ backupRetentionDays: 7
+ geoRedundantBackup: 'Disabled'
+ }
+ highAvailability: {
+ mode: 'Disabled'
+ }
+ availabilityZone: '1'
+ }
+}
+
+resource postgreSqlFirewallRule_TT2MuwakC 'Microsoft.DBforPostgreSQL/flexibleServers/firewallRules@2023-03-01-preview' = {
+ parent: postgreSqlFlexibleServer_UTKFzAL0U
+ name: 'AllowAllAzureIps'
+ properties: {
+ startIpAddress: '0.0.0.0'
+ endIpAddress: '0.0.0.0'
+ }
+}
+
+resource postgreSqlFlexibleServerDatabase_MVhrhEeMJ 'Microsoft.DBforPostgreSQL/flexibleServers/databases@2022-12-01' = {
+ parent: postgreSqlFlexibleServer_UTKFzAL0U
+ name: 'pgsqldb'
+ properties: {
+ }
+}
+
+resource keyVaultSecret_Ddsc3HjrA 'Microsoft.KeyVault/vaults/secrets@2023-02-01' = {
+ parent: keyVault_IeF8jZvXV
+ name: 'connectionString'
+ location: location
+ properties: {
+ value: 'Host=${postgreSqlFlexibleServer_UTKFzAL0U.properties.fullyQualifiedDomainName};Username=${administratorLogin};Password=${administratorLoginPassword}'
+ }
+}
diff --git a/playground/cdk/CdkSample.AppHost/pgsql2.module.bicep b/playground/cdk/CdkSample.AppHost/pgsql2.module.bicep
new file mode 100644
index 0000000000..d1cc554dff
--- /dev/null
+++ b/playground/cdk/CdkSample.AppHost/pgsql2.module.bicep
@@ -0,0 +1,65 @@
+targetScope = 'resourceGroup'
+
+@description('')
+param location string = resourceGroup().location
+
+@description('')
+param administratorLogin string
+
+@secure()
+@description('')
+param administratorLoginPassword string
+
+@description('')
+param principalId string
+
+@description('')
+param keyVaultName string
+
+
+resource keyVault_IeF8jZvXV 'Microsoft.KeyVault/vaults@2023-02-01' existing = {
+ name: keyVaultName
+}
+
+resource postgreSqlFlexibleServer_L4yCjMLWz 'Microsoft.DBforPostgreSQL/flexibleServers@2022-12-01' = {
+ name: toLower(take(concat('pgsql2', uniqueString(resourceGroup().id)), 24))
+ location: location
+ sku: {
+ name: 'Standard_B1ms'
+ tier: 'Burstable'
+ }
+ properties: {
+ administratorLogin: administratorLogin
+ administratorLoginPassword: administratorLoginPassword
+ version: '16'
+ storage: {
+ storageSizeGB: 32
+ }
+ backup: {
+ backupRetentionDays: 7
+ geoRedundantBackup: 'Disabled'
+ }
+ highAvailability: {
+ mode: 'Disabled'
+ }
+ availabilityZone: '1'
+ }
+}
+
+resource postgreSqlFirewallRule_b2WDQTOKx 'Microsoft.DBforPostgreSQL/flexibleServers/firewallRules@2023-03-01-preview' = {
+ parent: postgreSqlFlexibleServer_L4yCjMLWz
+ name: 'AllowAllAzureIps'
+ properties: {
+ startIpAddress: '0.0.0.0'
+ endIpAddress: '0.0.0.0'
+ }
+}
+
+resource keyVaultSecret_Ddsc3HjrA 'Microsoft.KeyVault/vaults/secrets@2023-02-01' = {
+ parent: keyVault_IeF8jZvXV
+ name: 'connectionString'
+ location: location
+ properties: {
+ value: 'Host=${postgreSqlFlexibleServer_L4yCjMLWz.properties.fullyQualifiedDomainName};Username=${administratorLogin};Password=${administratorLoginPassword}'
+ }
+}
diff --git a/playground/cdk/CdkSample.AppHost/sql.module.bicep b/playground/cdk/CdkSample.AppHost/sql.module.bicep
index 3091ae52f5..401a32590e 100644
--- a/playground/cdk/CdkSample.AppHost/sql.module.bicep
+++ b/playground/cdk/CdkSample.AppHost/sql.module.bicep
@@ -1,13 +1,13 @@
targetScope = 'resourceGroup'
@description('')
-param principalId string
+param location string = resourceGroup().location
@description('')
-param principalName string
+param principalId string
@description('')
-param location string = resourceGroup().location
+param principalName string
resource sqlServer_l5O9GRsSn 'Microsoft.Sql/servers@2022-08-01-preview' = {
diff --git a/playground/cdk/CdkSample.AppHost/storage.module.bicep b/playground/cdk/CdkSample.AppHost/storage.module.bicep
index 877a07f703..44f00a68cd 100644
--- a/playground/cdk/CdkSample.AppHost/storage.module.bicep
+++ b/playground/cdk/CdkSample.AppHost/storage.module.bicep
@@ -1,13 +1,13 @@
targetScope = 'resourceGroup'
@description('')
-param principalId string
+param location string = resourceGroup().location
@description('')
-param principalType string
+param principalId string
@description('')
-param location string = resourceGroup().location
+param principalType string
@description('')
param storagesku string
diff --git a/src/Aspire.Hosting.Azure/AzurePostgresResource.cs b/src/Aspire.Hosting.Azure/AzurePostgresResource.cs
index 987158fafa..c39ff98f5f 100644
--- a/src/Aspire.Hosting.Azure/AzurePostgresResource.cs
+++ b/src/Aspire.Hosting.Azure/AzurePostgresResource.cs
@@ -50,3 +50,50 @@ public class AzurePostgresResource(PostgresServerResource innerResource) :
///
public override ResourceAnnotationCollection Annotations => innerResource.Annotations;
}
+
+///
+/// Represents an resource for Azure Postgres Flexible Server.
+///
+/// that this resource wraps.
+/// Callback to configure construct.
+public class AzurePostgresConstructResource(PostgresServerResource innerResource, Action configureConstruct) :
+ AzureConstructResource(innerResource.Name, configureConstruct),
+ IResourceWithConnectionString
+{
+ ///
+ /// Gets the "connectionString" secret output reference from the bicep template for the Azure Postgres Flexible Server.
+ ///
+ public BicepSecretOutputReference ConnectionString => new("connectionString", this);
+
+ ///
+ /// Gets the connection template for the manifest for the Azure Postgres Flexible Server.
+ ///
+ public string ConnectionStringExpression => ConnectionString.ValueExpression;
+
+ ///
+ /// Gets the connection string for the Azure Postgres Flexible Server.
+ ///
+ /// The connection string.
+ public string? GetConnectionString() => ConnectionString.Value;
+
+ ///
+ /// Gets the connection string for the Azure Postgres Flexible Server.
+ ///
+ /// A to observe while waiting for the task to complete.
+ /// The connection string.
+ public async ValueTask GetConnectionStringAsync(CancellationToken cancellationToken = default)
+ {
+ if (ProvisioningTaskCompletionSource is not null)
+ {
+ await ProvisioningTaskCompletionSource.Task.WaitAsync(cancellationToken).ConfigureAwait(false);
+ }
+
+ return GetConnectionString();
+ }
+
+ ///
+ public override string Name => innerResource.Name;
+
+ ///
+ public override ResourceAnnotationCollection Annotations => innerResource.Annotations;
+}
diff --git a/src/Aspire.Hosting.Azure/Extensions/AzurePostgresExtensions.cs b/src/Aspire.Hosting.Azure/Extensions/AzurePostgresExtensions.cs
index 305624100b..b3f7083977 100644
--- a/src/Aspire.Hosting.Azure/Extensions/AzurePostgresExtensions.cs
+++ b/src/Aspire.Hosting.Azure/Extensions/AzurePostgresExtensions.cs
@@ -3,6 +3,9 @@
using Aspire.Hosting.ApplicationModel;
using Aspire.Hosting.Azure;
+using Azure.Provisioning;
+using Azure.Provisioning.KeyVaults;
+using Azure.Provisioning.PostgreSql;
namespace Aspire.Hosting;
@@ -83,10 +86,10 @@ private static IResourceBuilder ConfigureDefaults(this IR
.WithParameter(AzureBicepResource.KnownParameters.KeyVaultName);
}
- private static IResourceBuilder WithLoginAndPassword(
- this IResourceBuilder builder,
+ private static IResourceBuilder WithLoginAndPassword(
+ this IResourceBuilder builder,
IResourceBuilder? administratorLogin,
- IResourceBuilder? administratorLoginPassword)
+ IResourceBuilder? administratorLoginPassword) where T: AzureBicepResource
{
if (administratorLogin is null)
{
@@ -116,4 +119,124 @@ private static IResourceBuilder WithLoginAndPassword(
return builder;
}
+
+ internal static IResourceBuilder PublishAsAzurePostgresFlexibleServerConstruct(
+ this IResourceBuilder builder,
+ IResourceBuilder? administratorLogin = null,
+ IResourceBuilder? administratorLoginPassword = null,
+ Action, ResourceModuleConstruct, PostgreSqlFlexibleServer>? configureResource = null,
+ bool useProvisioner = false)
+ {
+ var configureConstruct = (ResourceModuleConstruct construct) =>
+ {
+ var administratorLogin = new Parameter("administratorLogin");
+ var administratorLoginPassword = new Parameter("administratorLoginPassword", isSecure: true);
+
+ var postgres = new PostgreSqlFlexibleServer(construct, administratorLogin, administratorLoginPassword, name: construct.Resource.Name);
+ postgres.AssignProperty(x => x.Sku.Name, "'Standard_B1ms'");
+ postgres.AssignProperty(x => x.Sku.Tier, "'Burstable'");
+ postgres.AssignProperty(x => x.Version, "'16'");
+ postgres.AssignProperty(x => x.HighAvailability.Mode, "'Disabled'");
+ postgres.AssignProperty(x => x.Storage.StorageSizeInGB, "32");
+ postgres.AssignProperty(x => x.Backup.BackupRetentionDays, "7");
+ postgres.AssignProperty(x => x.Backup.GeoRedundantBackup, "'Disabled'");
+ postgres.AssignProperty(x => x.AvailabilityZone, "'1'");
+
+ // Opens access to all Azure services.
+ var azureServicesFirewallRule = new PostgreSqlFirewallRule(construct, "0.0.0.0", "0.0.0.0", postgres, "AllowAllAzureIps");
+
+ if (builder.ApplicationBuilder.ExecutionContext.IsRunMode)
+ {
+ // Opens access to the Internet.
+ var openFirewallRule = new PostgreSqlFirewallRule(construct, "0.0.0.0", "255.255.255.255", postgres, "AllowAllIps");
+ }
+
+ List sqlDatabases = new List();
+ foreach (var databaseNames in builder.Resource.Databases)
+ {
+ var databaseName = databaseNames.Value;
+ var pgsqlDatabase = new PostgreSqlFlexibleServerDatabase(construct, postgres, databaseName);
+ sqlDatabases.Add(pgsqlDatabase);
+ }
+
+ var keyVault = KeyVault.FromExisting(construct, "keyVaultName");
+ _ = new KeyVaultSecret(construct, "connectionString", postgres.GetConnectionString(administratorLogin, administratorLoginPassword));
+
+ if (configureResource != null)
+ {
+ var azureResource = (AzurePostgresConstructResource)construct.Resource;
+ var azureResourceBuilder = builder.ApplicationBuilder.CreateResourceBuilder(azureResource);
+ configureResource(azureResourceBuilder, construct, postgres);
+ }
+ };
+
+ var resource = new AzurePostgresConstructResource(builder.Resource, configureConstruct);
+ var resourceBuilder = builder.ApplicationBuilder.CreateResourceBuilder(resource)
+ .WithParameter(AzureBicepResource.KnownParameters.PrincipalId)
+ .WithParameter(AzureBicepResource.KnownParameters.KeyVaultName)
+ .WithManifestPublishingCallback(resource.WriteToManifest)
+ .WithLoginAndPassword(administratorLogin, administratorLoginPassword);
+
+ if (builder.ApplicationBuilder.ExecutionContext.IsRunMode)
+ {
+ resourceBuilder.WithParameter(AzureBicepResource.KnownParameters.PrincipalType);
+ }
+
+ if (useProvisioner)
+ {
+ // Used to hold a reference to the azure surrogate for use with the provisioner.
+ builder.WithAnnotation(new AzureBicepResourceAnnotation(resource));
+ builder.WithConnectionStringRedirection(resource);
+
+ // Remove the container annotation so that DCP doesn't do anything with it.
+ if (builder.Resource.Annotations.OfType().SingleOrDefault() is { } containerAnnotation)
+ {
+ builder.Resource.Annotations.Remove(containerAnnotation);
+ }
+ }
+
+ return builder;
+ }
+
+ ///
+ /// Configures Postgres Server resource to be deployed as Azure Postgres Flexible Server.
+ ///
+ /// The builder.
+ ///
+ ///
+ /// Callback to configure Azure resource.
+ /// A reference to the builder.
+ public static IResourceBuilder PublishAsAzurePostgresFlexibleServerConstruct(
+ this IResourceBuilder builder,
+ IResourceBuilder? administratorLogin = null,
+ IResourceBuilder? administratorLoginPassword = null,
+ Action, ResourceModuleConstruct, PostgreSqlFlexibleServer>? configureResource = null)
+ {
+ return builder.PublishAsAzurePostgresFlexibleServerConstruct(
+ administratorLogin,
+ administratorLoginPassword,
+ configureResource,
+ useProvisioner: false);
+ }
+
+ ///
+ /// Configures resource to use Azure for local development and when doing a deployment via the Azure Developer CLI.
+ ///
+ /// The builder.
+ ///
+ ///
+ /// Callback to configure Azure resource.
+ /// A reference to the builder.
+ public static IResourceBuilder AsAzurePostgresFlexibleServerConstruct(
+ this IResourceBuilder builder,
+ IResourceBuilder? administratorLogin = null,
+ IResourceBuilder? administratorLoginPassword = null,
+ Action, ResourceModuleConstruct, PostgreSqlFlexibleServer>? configureResource = null)
+ {
+ return builder.PublishAsAzurePostgresFlexibleServerConstruct(
+ administratorLogin,
+ administratorLoginPassword,
+ configureResource,
+ useProvisioner: true);
+ }
}
diff --git a/src/Aspire.Hosting.Azure/Extensions/AzureRedisExtensions.cs b/src/Aspire.Hosting.Azure/Extensions/AzureRedisExtensions.cs
index 299cbb0a2f..4322dabf6c 100644
--- a/src/Aspire.Hosting.Azure/Extensions/AzureRedisExtensions.cs
+++ b/src/Aspire.Hosting.Azure/Extensions/AzureRedisExtensions.cs
@@ -119,10 +119,7 @@ internal static IResourceBuilder PublishAsAzureRedisConstruct(thi
if (builder.ApplicationBuilder.ExecutionContext.IsRunMode)
{
- if (builder.ApplicationBuilder.ExecutionContext.IsRunMode)
- {
- resourceBuilder.WithParameter(AzureBicepResource.KnownParameters.PrincipalType);
- }
+ resourceBuilder.WithParameter(AzureBicepResource.KnownParameters.PrincipalType);
}
if (useProvisioner)
diff --git a/src/Aspire.Hosting.Azure/Extensions/AzureSqlExtensions.cs b/src/Aspire.Hosting.Azure/Extensions/AzureSqlExtensions.cs
index 9e8c9cf45e..09e3055e9b 100644
--- a/src/Aspire.Hosting.Azure/Extensions/AzureSqlExtensions.cs
+++ b/src/Aspire.Hosting.Azure/Extensions/AzureSqlExtensions.cs
@@ -95,7 +95,7 @@ internal static IResourceBuilder PublishAsAzureSqlDatab
// the principalType.
sqlServer.AssignProperty(x => x.Administrators.PrincipalType, construct.PrincipalTypeParameter);
- var sqlFirewall = new SqlFirewallRule(construct);
+ var sqlFirewall = new SqlFirewallRule(construct, sqlServer);
sqlFirewall.AssignProperty(x => x.StartIPAddress, "'0.0.0.0'");
sqlFirewall.AssignProperty(x => x.EndIPAddress, "'255.255.255.255'");
}