From f303bf448a4a88c9c42cb7f7d9a4159e2410541d Mon Sep 17 00:00:00 2001
From: Bart Koelman <104792814+bart-vmware@users.noreply.github.com>
Date: Tue, 21 Apr 2026 15:04:27 +0200
Subject: [PATCH 1/7] Add property to disable built-in post-processors,
including sample code for binding third-party brokers
---
.../ConnectorConfigureOptionsBuilder.cs | 79 ++++++++++++++++
.../src/Connectors/ConnectorConfigurer.cs | 7 +-
.../src/Connectors/PublicAPI.Unshipped.txt | 2 +
.../PostgreSql/PostgreSqlConnectorTest.cs | 92 +++++++++++++++++++
4 files changed, 178 insertions(+), 2 deletions(-)
diff --git a/src/Connectors/src/Connectors/ConnectorConfigureOptionsBuilder.cs b/src/Connectors/src/Connectors/ConnectorConfigureOptionsBuilder.cs
index 85f4a87b56..46dd74a382 100644
--- a/src/Connectors/src/Connectors/ConnectorConfigureOptionsBuilder.cs
+++ b/src/Connectors/src/Connectors/ConnectorConfigureOptionsBuilder.cs
@@ -13,4 +13,83 @@ public sealed class ConnectorConfigureOptionsBuilder
/// is false.
///
public bool DetectConfigurationChanges { get; set; }
+
+ ///
+ /// Gets or sets a value indicating whether to turn off the built-in service broker support. This is false by default, but should be set to
+ /// true when using custom logic to convert platform-based credentials to driver-specific configuration keys.
+ ///
+ ///
+ /// For example, to use a third-party Cloud Foundry service broker, the following code can be used to map the PostgreSQL credentials to the format that
+ ///
+ /// NpgsqlConnectionStringBuilder
+ ///
+ /// expects:
+ /// configure.SkipDefaultServiceBindings = true, null);
+ /// var app = builder.Build();
+ ///
+ /// var factory = app.Services.GetRequiredService>();
+ ///
+ /// PostgreSqlOptions productsDbOptions = factory.Get("products-db").Options;
+ /// Console.WriteLine(productsDbOptions.ConnectionString);
+ /// // Database=product-database;Host=example.cloud.com;Password=products-secret;Port=2345;Username=products-user
+ ///
+ /// PostgreSqlOptions ordersDbOptions = factory.Get("orders-db").Options;
+ /// Console.WriteLine(ordersDbOptions.ConnectionString);
+ /// // Database=order-database;Host=example.cloud.com;Password=orders-secret;Port=2345;Username=orders-user
+ ///
+ /// void MapCustomServiceBindings(string brokerName)
+ /// {
+ /// var options = builder.Configuration.GetSection("vcap").Get();
+ ///
+ /// foreach (CloudFoundryService service in options?.Services
+ /// .Where(pair => pair.Key == brokerName)
+ /// .SelectMany(pair => pair.Value) ?? [])
+ /// {
+ /// builder.Configuration.AddInMemoryCollection(new Dictionary
+ /// {
+ /// // Map credentials into the property names expected by NpgsqlConnectionStringBuilder.
+ /// [$"steeltoe:service-bindings:postgresql:{service.Name}:host"] = service.Credentials["custom-hostname-key"].Value,
+ /// [$"steeltoe:service-bindings:postgresql:{service.Name}:port"] = service.Credentials["custom-port-key"].Value,
+ /// [$"steeltoe:service-bindings:postgresql:{service.Name}:username"] = service.Credentials["custom-username-key"].Value,
+ /// [$"steeltoe:service-bindings:postgresql:{service.Name}:password"] = service.Credentials["custom-password-key"].Value,
+ /// [$"steeltoe:service-bindings:postgresql:{service.Name}:database"] = service.Credentials["custom-database-name-key"].Value
+ /// });
+ /// }
+ /// }
+ /// ]]>
+ ///
+ ///
+ ///
+ public bool SkipDefaultServiceBindings { get; set; }
}
diff --git a/src/Connectors/src/Connectors/ConnectorConfigurer.cs b/src/Connectors/src/Connectors/ConnectorConfigurer.cs
index 2bb05f61b5..ba77bbf605 100644
--- a/src/Connectors/src/Connectors/ConnectorConfigurer.cs
+++ b/src/Connectors/src/Connectors/ConnectorConfigurer.cs
@@ -20,8 +20,11 @@ public static void Configure(IConfigurationBuilder builder, Acti
var optionsBuilder = new ConnectorConfigureOptionsBuilder();
configureAction?.Invoke(optionsBuilder);
- builder.AddCloudFoundryServiceBindings();
- builder.AddKubernetesServiceBindings();
+ if (!optionsBuilder.SkipDefaultServiceBindings)
+ {
+ builder.AddCloudFoundryServiceBindings();
+ builder.AddKubernetesServiceBindings();
+ }
RegisterPostProcessor(connectionStringPostProcessor, builder, optionsBuilder.DetectConfigurationChanges);
}
diff --git a/src/Connectors/src/Connectors/PublicAPI.Unshipped.txt b/src/Connectors/src/Connectors/PublicAPI.Unshipped.txt
index 7dc5c58110..9269e14767 100644
--- a/src/Connectors/src/Connectors/PublicAPI.Unshipped.txt
+++ b/src/Connectors/src/Connectors/PublicAPI.Unshipped.txt
@@ -1 +1,3 @@
#nullable enable
+Steeltoe.Connectors.ConnectorConfigureOptionsBuilder.SkipDefaultServiceBindings.get -> bool
+Steeltoe.Connectors.ConnectorConfigureOptionsBuilder.SkipDefaultServiceBindings.set -> void
diff --git a/src/Connectors/test/Connectors.Test/PostgreSql/PostgreSqlConnectorTest.cs b/src/Connectors/test/Connectors.Test/PostgreSql/PostgreSqlConnectorTest.cs
index 9a158bb430..9db3f840b4 100644
--- a/src/Connectors/test/Connectors.Test/PostgreSql/PostgreSqlConnectorTest.cs
+++ b/src/Connectors/test/Connectors.Test/PostgreSql/PostgreSqlConnectorTest.cs
@@ -9,6 +9,7 @@
using Npgsql;
using Steeltoe.Common.HealthChecks;
using Steeltoe.Common.TestResources;
+using Steeltoe.Configuration.CloudFoundry;
using Steeltoe.Configuration.CloudFoundry.ServiceBindings;
using Steeltoe.Configuration.Kubernetes.ServiceBindings;
using Steeltoe.Connectors.PostgreSql;
@@ -394,6 +395,97 @@ public async Task Binds_options_with_Kubernetes_service_bindings()
}, options => options.WithoutStrictOrdering());
}
+ [Fact]
+ public async Task Binds_options_with_third_party_service_bindings()
+ {
+ var appSettings = new Dictionary
+ {
+ ["Steeltoe:Client:PostgreSql:products-db:ConnectionString"] = "Include Error Detail=true;host=localhost",
+ ["Steeltoe:Client:PostgreSql:orders-db:ConnectionString"] = "Log Parameters=true;port=9999"
+ };
+
+ var reader = new CloudFoundryMemorySettingsReader
+ {
+ ServicesJson = """
+ {
+ "custom-postgres-broker": [
+ {
+ "name": "products-db",
+ "credentials": {
+ "custom-hostname-key": "example.cloud.com",
+ "custom-port-key": 2345,
+ "custom-username-key": "products-user",
+ "custom-password-key": "products-secret",
+ "custom-database-name-key": "product-database"
+ }
+ },
+ {
+ "name": "orders-db",
+ "credentials": {
+ "custom-hostname-key": "example.cloud.com",
+ "custom-port-key": 2345,
+ "custom-username-key": "orders-user",
+ "custom-password-key": "orders-secret",
+ "custom-database-name-key": "order-database"
+ }
+ },
+ ]
+ }
+ """
+ };
+
+ WebApplicationBuilder builder = TestWebApplicationBuilderFactory.Create();
+ builder.Configuration.AddInMemoryCollection(appSettings);
+ builder.Configuration.AddCloudFoundry(reader);
+ MapCustomServiceBindings("custom-postgres-broker");
+ builder.AddPostgreSql(options => options.SkipDefaultServiceBindings = true, null);
+ await using WebApplication app = builder.Build();
+
+ var optionsMonitor = app.Services.GetRequiredService>();
+
+ PostgreSqlOptions productsDbOptions = optionsMonitor.Get("products-db");
+
+ ExtractConnectionStringParameters(productsDbOptions.ConnectionString).Should().BeEquivalentTo(new List
+ {
+ "Include Error Detail=True",
+ "Host=example.cloud.com",
+ "Port=2345",
+ "Database=product-database",
+ "Username=products-user",
+ "Password=products-secret"
+ }, options => options.WithoutStrictOrdering());
+
+ PostgreSqlOptions ordersDbOptions = optionsMonitor.Get("orders-db");
+
+ ExtractConnectionStringParameters(ordersDbOptions.ConnectionString).Should().BeEquivalentTo(new List
+ {
+ "Log Parameters=True",
+ "Host=example.cloud.com",
+ "Port=2345",
+ "Database=order-database",
+ "Username=orders-user",
+ "Password=orders-secret"
+ }, options => options.WithoutStrictOrdering());
+
+ void MapCustomServiceBindings(string brokerName)
+ {
+ var options = builder.Configuration.GetSection("vcap").Get();
+
+ foreach (CloudFoundryService service in options?.Services.Where(pair => pair.Key == brokerName).SelectMany(pair => pair.Value) ?? [])
+ {
+ builder.Configuration.AddInMemoryCollection(new Dictionary
+ {
+ // Map credentials into the property names expected by NpgsqlConnectionStringBuilder.
+ [$"steeltoe:service-bindings:postgresql:{service.Name}:host"] = service.Credentials["custom-hostname-key"].Value,
+ [$"steeltoe:service-bindings:postgresql:{service.Name}:port"] = service.Credentials["custom-port-key"].Value,
+ [$"steeltoe:service-bindings:postgresql:{service.Name}:username"] = service.Credentials["custom-username-key"].Value,
+ [$"steeltoe:service-bindings:postgresql:{service.Name}:password"] = service.Credentials["custom-password-key"].Value,
+ [$"steeltoe:service-bindings:postgresql:{service.Name}:database"] = service.Credentials["custom-database-name-key"].Value
+ });
+ }
+ }
+ }
+
[Fact]
public async Task Registers_ConnectorFactory()
{
From 66157c8f6ff833146fa52ab6417b54c9f7d6607d Mon Sep 17 00:00:00 2001
From: Bart Koelman <104792814+bart-vmware@users.noreply.github.com>
Date: Tue, 21 Apr 2026 17:12:22 +0200
Subject: [PATCH 2/7] Update links to supported service brokers
---
.../PostProcessors/MongoDbCloudFoundryPostProcessor.cs | 2 +-
.../PostProcessors/MySqlCloudFoundryPostProcessor.cs | 6 +++---
.../PostProcessors/PostgreSqlCloudFoundryPostProcessor.cs | 6 +++---
.../PostProcessors/RabbitMQCloudFoundryPostProcessor.cs | 2 +-
.../PostProcessors/RedisCloudFoundryPostProcessor.cs | 7 +++----
.../PostProcessors/SqlServerCloudFoundryPostProcessor.cs | 4 ++--
6 files changed, 13 insertions(+), 14 deletions(-)
diff --git a/src/Configuration/src/CloudFoundry/ServiceBindings/PostProcessors/MongoDbCloudFoundryPostProcessor.cs b/src/Configuration/src/CloudFoundry/ServiceBindings/PostProcessors/MongoDbCloudFoundryPostProcessor.cs
index 604e3c1fcd..85426606fe 100644
--- a/src/Configuration/src/CloudFoundry/ServiceBindings/PostProcessors/MongoDbCloudFoundryPostProcessor.cs
+++ b/src/Configuration/src/CloudFoundry/ServiceBindings/PostProcessors/MongoDbCloudFoundryPostProcessor.cs
@@ -16,7 +16,7 @@ public override void PostProcessConfiguration(PostProcessorConfigurationProvider
// Mapping from CloudFoundry service binding credentials to driver-specific connection string parameters.
// The available credentials are documented at:
- // - Azure Service Broker: https://techdocs.broadcom.com/us/en/vmware-tanzu/platform-services/tanzu-cloud-service-broker-for-microsoft-azure/1-13/csb-azure/reference-azure-cosmosdb-mongo.html#binding-creds
+ // - Azure Service Broker: https://techdocs.broadcom.com/us/en/vmware-tanzu/platform/cloud-service-broker-azure/1-13/csb-azure/reference-azure-cosmosdb-mongo.html#binding-creds
mapper.MapFromTo("credentials:uri", "url");
diff --git a/src/Configuration/src/CloudFoundry/ServiceBindings/PostProcessors/MySqlCloudFoundryPostProcessor.cs b/src/Configuration/src/CloudFoundry/ServiceBindings/PostProcessors/MySqlCloudFoundryPostProcessor.cs
index b70f530628..bca767b744 100644
--- a/src/Configuration/src/CloudFoundry/ServiceBindings/PostProcessors/MySqlCloudFoundryPostProcessor.cs
+++ b/src/Configuration/src/CloudFoundry/ServiceBindings/PostProcessors/MySqlCloudFoundryPostProcessor.cs
@@ -16,9 +16,9 @@ public override void PostProcessConfiguration(PostProcessorConfigurationProvider
// Mapping from CloudFoundry service binding credentials to driver-specific connection string parameters.
// The available credentials are documented at:
- // - Tanzu Broker: https://techdocs.broadcom.com/us/en/vmware-tanzu/data-solutions/tanzu-for-mysql-on-cloud-foundry/10-0/mysql-for-tpcf/use.html#vcap
- // - GCP Service Broker: https://techdocs.broadcom.com/us/en/vmware-tanzu/platform-services/tanzu-cloud-service-broker-for-gcp/1-9/csb-gcp/reference-gcp-mysql.html#binding-creds
- // - AWS Service Broker: https://techdocs.broadcom.com/us/en/vmware-tanzu/platform-services/tanzu-cloud-service-broker-for-aws/1-14/csb-aws/reference-aws-mysql.html#binding-creds
+ // - Tanzu Broker: https://techdocs.broadcom.com/us/en/vmware-tanzu/platform/tanzu-mysql-tanzu-platform/10-1/mysql-tp/use.html#vcap
+ // - GCP Service Broker: https://techdocs.broadcom.com/us/en/vmware-tanzu/platform/cloud-service-broker-gcp/1-8/csb-gcp/reference-gcp-mysql.html#binding-creds
+ // - AWS Service Broker: https://techdocs.broadcom.com/us/en/vmware-tanzu/platform/cloud-service-broker-aws/1-15/csb-aws/reference-aws-mysql.html#binding-creds
mapper.MapFromTo("credentials:hostname", "host");
mapper.MapFromTo("credentials:port", "port");
diff --git a/src/Configuration/src/CloudFoundry/ServiceBindings/PostProcessors/PostgreSqlCloudFoundryPostProcessor.cs b/src/Configuration/src/CloudFoundry/ServiceBindings/PostProcessors/PostgreSqlCloudFoundryPostProcessor.cs
index e044a20892..2e54c28d5a 100644
--- a/src/Configuration/src/CloudFoundry/ServiceBindings/PostProcessors/PostgreSqlCloudFoundryPostProcessor.cs
+++ b/src/Configuration/src/CloudFoundry/ServiceBindings/PostProcessors/PostgreSqlCloudFoundryPostProcessor.cs
@@ -22,9 +22,9 @@ public override void PostProcessConfiguration(PostProcessorConfigurationProvider
// Mapping from CloudFoundry service binding credentials to driver-specific connection string parameters.
// The available credentials are documented at:
- // - Tanzu Broker: https://techdocs.broadcom.com/us/en/vmware-tanzu/data-solutions/tanzu-for-postgres-on-cloud-foundry/10-1/postgres/app-setup-single-instance-service-guide.html
- // - GCP Service Broker: https://techdocs.broadcom.com/us/en/vmware-tanzu/platform-services/tanzu-cloud-service-broker-for-gcp/1-9/csb-gcp/reference-gcp-postgresql.html#binding-creds
- // - AWS Service Broker: https://techdocs.broadcom.com/us/en/vmware-tanzu/platform-services/tanzu-cloud-service-broker-for-aws/1-14/csb-aws/reference-aws-postgres.html#binding-creds
+ // - Tanzu Broker: https://techdocs.broadcom.com/us/en/vmware-tanzu/platform/tanzu-postgres-tanzu-platform/10-2/postgres-tp/app-setup-single-instance-service-guide.html
+ // - GCP Service Broker: https://techdocs.broadcom.com/us/en/vmware-tanzu/platform/cloud-service-broker-gcp/1-8/csb-gcp/reference-gcp-postgresql.html#binding-creds
+ // - AWS Service Broker: https://techdocs.broadcom.com/us/en/vmware-tanzu/platform/cloud-service-broker-aws/1-15/csb-aws/reference-aws-postgres.html#binding-creds
string? hosts = mapper.MapArrayFromTo("credentials:hosts", "host", HostsSeparator);
diff --git a/src/Configuration/src/CloudFoundry/ServiceBindings/PostProcessors/RabbitMQCloudFoundryPostProcessor.cs b/src/Configuration/src/CloudFoundry/ServiceBindings/PostProcessors/RabbitMQCloudFoundryPostProcessor.cs
index 8849fc6598..b5afd85194 100644
--- a/src/Configuration/src/CloudFoundry/ServiceBindings/PostProcessors/RabbitMQCloudFoundryPostProcessor.cs
+++ b/src/Configuration/src/CloudFoundry/ServiceBindings/PostProcessors/RabbitMQCloudFoundryPostProcessor.cs
@@ -16,7 +16,7 @@ public override void PostProcessConfiguration(PostProcessorConfigurationProvider
// Mapping from CloudFoundry service binding credentials to driver-specific connection string parameters.
// The available credentials are documented at:
- // - Tanzu Broker: https://techdocs.broadcom.com/us/en/vmware-tanzu/data-solutions/tanzu-rabbitmq-on-cloud-foundry/10-0/tanzu-rabbitmq-cloud-foundry/reference.html
+ // - Tanzu Broker: https://techdocs.broadcom.com/us/en/vmware-tanzu/platform/tanzu-rabbitmq-tanzu-platform/10-0/rabbitmq-tp/use.html#call
string? useTlsValue = mapper.MapFromTo("credentials:ssl", "useTls");
string fromProtocol = bool.TryParse(useTlsValue, out bool useTls) && useTls ? "amqp+ssl" : "amqp";
diff --git a/src/Configuration/src/CloudFoundry/ServiceBindings/PostProcessors/RedisCloudFoundryPostProcessor.cs b/src/Configuration/src/CloudFoundry/ServiceBindings/PostProcessors/RedisCloudFoundryPostProcessor.cs
index 81880bc28c..56ceb8890d 100644
--- a/src/Configuration/src/CloudFoundry/ServiceBindings/PostProcessors/RedisCloudFoundryPostProcessor.cs
+++ b/src/Configuration/src/CloudFoundry/ServiceBindings/PostProcessors/RedisCloudFoundryPostProcessor.cs
@@ -16,10 +16,9 @@ public override void PostProcessConfiguration(PostProcessorConfigurationProvider
// Mapping from CloudFoundry service binding credentials to driver-specific connection string parameters.
// The available credentials are documented at:
- // - Tanzu Broker (Redis): https://techdocs.broadcom.com/us/en/vmware-tanzu/data-solutions/redis-for-tanzu-application-service/3-5/redis-for-tas/using.html#use-redis-service-in-app
- // - Tanzu Broker (Valkey): https://techdocs.broadcom.com/us/en/vmware-tanzu/data-solutions/tanzu-for-valkey-on-cloud-foundry/4-0/valkey-on-cf/using.html#use-valkey-service-in-app
- // - Azure Service Broker: https://techdocs.broadcom.com/us/en/vmware-tanzu/platform-services/tanzu-cloud-service-broker-for-microsoft-azure/1-13/csb-azure/reference-azure-redis.html#binding-creds
- // - AWS Service Broker: https://techdocs.broadcom.com/us/en/vmware-tanzu/platform-services/tanzu-cloud-service-broker-for-aws/1-14/csb-aws/reference-aws-redis.html#binding-creds
+ // - Tanzu Broker: https://techdocs.broadcom.com/us/en/vmware-tanzu/platform/tanzu-valkey-tanzu-platform/10-2/valkey-tp/using.html#use-valkey-service-in-app
+ // - Azure Service Broker: https://techdocs.broadcom.com/us/en/vmware-tanzu/platform/cloud-service-broker-azure/1-13/csb-azure/reference-azure-redis.html
+ // - AWS Service Broker: https://techdocs.broadcom.com/us/en/vmware-tanzu/platform/cloud-service-broker-aws/1-15/csb-aws/reference-aws-redis.html
mapper.MapFromTo("credentials:host", "host");
mapper.MapFromTo("credentials:port", "port");
diff --git a/src/Configuration/src/CloudFoundry/ServiceBindings/PostProcessors/SqlServerCloudFoundryPostProcessor.cs b/src/Configuration/src/CloudFoundry/ServiceBindings/PostProcessors/SqlServerCloudFoundryPostProcessor.cs
index 4b595cf7d6..f4f38827fa 100644
--- a/src/Configuration/src/CloudFoundry/ServiceBindings/PostProcessors/SqlServerCloudFoundryPostProcessor.cs
+++ b/src/Configuration/src/CloudFoundry/ServiceBindings/PostProcessors/SqlServerCloudFoundryPostProcessor.cs
@@ -16,8 +16,8 @@ public override void PostProcessConfiguration(PostProcessorConfigurationProvider
// Mapping from CloudFoundry service binding credentials to driver-specific connection string parameters.
// The available credentials are documented at:
- // - Azure Service Broker: https://techdocs.broadcom.com/us/en/vmware-tanzu/platform-services/tanzu-cloud-service-broker-for-microsoft-azure/1-13/csb-azure/reference-azure-mssql-db.html#binding-creds
- // - AWS Service Broker: https://techdocs.broadcom.com/us/en/vmware-tanzu/platform-services/tanzu-cloud-service-broker-for-aws/1-14/csb-aws/reference-aws-mssql.html#binding-creds
+ // - Azure Service Broker: https://techdocs.broadcom.com/us/en/vmware-tanzu/platform/cloud-service-broker-azure/1-13/csb-azure/reference-azure-mssql-db.html#binding-creds
+ // - AWS Service Broker: https://techdocs.broadcom.com/us/en/vmware-tanzu/platform/cloud-service-broker-aws/1-15/csb-aws/reference-aws-mssql.html#binding-creds
mapper.MapFromTo("credentials:hostname", "Data Source");
mapper.MapFromAppendTo("credentials:port", "Data Source", ",");
From 17eb384f9a3dd7b0a8503b1efdfff6a18dcf26f6 Mon Sep 17 00:00:00 2001
From: Bart Koelman <104792814+bart-vmware@users.noreply.github.com>
Date: Wed, 22 Apr 2026 12:56:25 +0200
Subject: [PATCH 3/7] Review feedback: adapt documentation
---
.../ConnectorConfigureOptionsBuilder.cs | 60 ++++++++++---------
1 file changed, 32 insertions(+), 28 deletions(-)
diff --git a/src/Connectors/src/Connectors/ConnectorConfigureOptionsBuilder.cs b/src/Connectors/src/Connectors/ConnectorConfigureOptionsBuilder.cs
index 46dd74a382..746fe5617e 100644
--- a/src/Connectors/src/Connectors/ConnectorConfigureOptionsBuilder.cs
+++ b/src/Connectors/src/Connectors/ConnectorConfigureOptionsBuilder.cs
@@ -19,39 +19,43 @@ public sealed class ConnectorConfigureOptionsBuilder
/// true when using custom logic to convert platform-based credentials to driver-specific configuration keys.
///
///
- /// For example, to use a third-party Cloud Foundry service broker, the following code can be used to map the PostgreSQL credentials to the format that
+ /// For example, to use a third-party Cloud Foundry service broker that sets the
+ ///
+ /// VCAP_SERVICES
+ ///
+ /// environment variable to:
+ ///
+ /// {
+ /// "custom-postgres-broker": [
+ /// {
+ /// "name": "products-db",
+ /// "credentials": {
+ /// "custom-hostname-key": "example.cloud.com",
+ /// "custom-port-key": 2345,
+ /// "custom-username-key": "products-user",
+ /// "custom-password-key": "products-secret",
+ /// "custom-database-name-key": "product-database"
+ /// }
+ /// },
+ /// {
+ /// "name": "orders-db",
+ /// "credentials": {
+ /// "custom-hostname-key": "example.cloud.com",
+ /// "custom-port-key": 2345,
+ /// "custom-username-key": "orders-user",
+ /// "custom-password-key": "orders-secret",
+ /// "custom-database-name-key": "order-database"
+ /// }
+ /// }
+ /// ]
+ /// }
+ ///
+ /// The following code can be used to map the PostgreSQL credentials to the format that
///
/// NpgsqlConnectionStringBuilder
///
/// expects:
///
Date: Thu, 23 Apr 2026 12:30:25 +0200
Subject: [PATCH 4/7] Bugfix: preserve custom query string parameters in local
RabbitMQ URI; relax other parsers to allow unknown parameters to support
third-party brokers
---
.../MongoDb/MongoDbConnectionStringBuilder.cs | 57 +++++--------------
.../RabbitMQConnectionStringBuilder.cs | 34 ++++++++---
.../Redis/RedisConnectionStringBuilder.cs | 20 +------
.../MongoDbConnectionStringBuilderTest.cs | 6 +-
.../MongoDb/MongoDbConnectorTest.cs | 2 +-
.../RabbitMQConnectionStringBuilderTest.cs | 33 ++++++++---
.../RabbitMQ/RabbitMQConnectorTest.cs | 12 ++--
.../Redis/RedisConnectionStringBuilderTest.cs | 6 +-
8 files changed, 81 insertions(+), 89 deletions(-)
diff --git a/src/Connectors/src/Connectors/MongoDb/MongoDbConnectionStringBuilder.cs b/src/Connectors/src/Connectors/MongoDb/MongoDbConnectionStringBuilder.cs
index f70ac70a79..ec3a8c6c73 100644
--- a/src/Connectors/src/Connectors/MongoDb/MongoDbConnectionStringBuilder.cs
+++ b/src/Connectors/src/Connectors/MongoDb/MongoDbConnectionStringBuilder.cs
@@ -22,7 +22,7 @@ internal sealed class MongoDbConnectionStringBuilder : IConnectionStringBuilder
public string ConnectionString
{
get => ToConnectionString();
- set => FromConnectionString(value, false);
+ set => FromConnectionString(value);
}
///
@@ -37,14 +37,8 @@ public object? this[string keyword]
return ConnectionString;
}
- // Allow getting unknown keyword, if it was set earlier. We don't pretend to know all valid query string parameters.
- if (_settings.TryGetValue(keyword, out string? value))
- {
- return value;
- }
-
- AssertIsKnownKeyword(keyword);
- return null;
+ // Allow getting unknown keyword. We don't pretend to know all valid query string parameters.
+ return _settings.GetValueOrDefault(keyword);
}
set
{
@@ -52,7 +46,7 @@ public object? this[string keyword]
if (string.Equals(keyword, KnownKeywords.Url, StringComparison.OrdinalIgnoreCase))
{
- FromConnectionString(value?.ToString(), true);
+ ConnectionString = value?.ToString();
}
else
{
@@ -106,9 +100,9 @@ private string ToConnectionString()
var queryString = default(QueryString);
- foreach ((string keyword, string value) in _settings.Where(pair => !KnownKeywords.Exists(pair.Key)))
+ foreach ((string name, string value) in _settings.Where(pair => !KnownKeywords.Exists(pair.Key)))
{
- queryString = queryString.Add(keyword, value);
+ queryString = queryString.Add(name, value);
}
builder.Query = queryString.Value;
@@ -116,19 +110,9 @@ private string ToConnectionString()
return builder.Uri.AbsoluteUri;
}
- private void FromConnectionString(string? connectionString, bool preserveUnknownSettings)
+ private void FromConnectionString(string? connectionString)
{
- if (preserveUnknownSettings)
- {
- foreach (string keywordToRemove in _settings.Keys.Where(KnownKeywords.Exists).ToArray())
- {
- _settings.Remove(keywordToRemove);
- }
- }
- else
- {
- _settings.Clear();
- }
+ _settings.Clear();
if (!string.IsNullOrEmpty(connectionString))
{
@@ -140,7 +124,7 @@ private void FromConnectionString(string? connectionString, bool preserveUnknown
#pragma warning restore S3717 // Track use of "NotImplementedException"
}
- // MongoDB allows semicolon as separator for query string parameters, to provide backwards compatibility.
+ // MongoDB allows semicolon as separator between query string parameters for backward compatibility.
connectionString = connectionString.Replace(';', '&');
var uri = new Uri(connectionString);
@@ -169,31 +153,20 @@ private void FromConnectionString(string? connectionString, bool preserveUnknown
_settings[KnownKeywords.AuthenticationDatabase] = Uri.UnescapeDataString(uri.AbsolutePath[1..]);
}
- NameValueCollection queryCollection = HttpUtility.ParseQueryString(uri.Query);
+ NameValueCollection queryString = HttpUtility.ParseQueryString(uri.Query);
- foreach (string? key in queryCollection.AllKeys)
+ foreach (string remainingKeyword in queryString.AllKeys.Where(key => key != null && !KnownKeywords.Exists(key)).Cast())
{
- if (key != null)
- {
- string? value = queryCollection.Get(key);
+ string? value = queryString.Get(remainingKeyword);
- if (value != null)
- {
- _settings[key] = value;
- }
+ if (value != null)
+ {
+ _settings[remainingKeyword] = value;
}
}
}
}
- private static void AssertIsKnownKeyword(string keyword)
- {
- if (!KnownKeywords.Exists(keyword))
- {
- throw new ArgumentException($"Keyword not supported: '{keyword}'.", nameof(keyword));
- }
- }
-
private static class KnownKeywords
{
public const string Url = "url";
diff --git a/src/Connectors/src/Connectors/RabbitMQ/RabbitMQConnectionStringBuilder.cs b/src/Connectors/src/Connectors/RabbitMQ/RabbitMQConnectionStringBuilder.cs
index 9fe7382933..ccc369197f 100644
--- a/src/Connectors/src/Connectors/RabbitMQ/RabbitMQConnectionStringBuilder.cs
+++ b/src/Connectors/src/Connectors/RabbitMQ/RabbitMQConnectionStringBuilder.cs
@@ -2,8 +2,11 @@
// The .NET Foundation licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information.
+using System.Collections.Specialized;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
+using System.Web;
+using Microsoft.AspNetCore.Http;
namespace Steeltoe.Connectors.RabbitMQ;
@@ -28,19 +31,18 @@ public object? this[string keyword]
get
{
ArgumentException.ThrowIfNullOrWhiteSpace(keyword);
- AssertIsKnownKeyword(keyword);
if (string.Equals(keyword, KnownKeywords.Url, StringComparison.OrdinalIgnoreCase))
{
return ConnectionString;
}
+ // Allow getting unknown keyword. We don't pretend to know all valid query string parameters.
return _settings.GetValueOrDefault(keyword);
}
set
{
ArgumentException.ThrowIfNullOrWhiteSpace(keyword);
- AssertIsKnownKeyword(keyword);
if (string.Equals(keyword, KnownKeywords.Url, StringComparison.OrdinalIgnoreCase))
{
@@ -56,6 +58,7 @@ public object? this[string keyword]
}
else
{
+ // Allow setting unknown keyword. We don't pretend to know all valid query string parameters.
_settings[keyword] = stringValue;
}
}
@@ -97,6 +100,15 @@ private string ToConnectionString()
builder.Path = Uri.EscapeDataString(virtualHost);
}
+ var queryString = default(QueryString);
+
+ foreach ((string name, string value) in _settings.Where(pair => !KnownKeywords.Exists(pair.Key)))
+ {
+ queryString = queryString.Add(name, value);
+ }
+
+ builder.Query = queryString.Value;
+
return builder.Uri.AbsoluteUri;
}
@@ -132,14 +144,18 @@ private void FromConnectionString(string? connectionString)
{
_settings[KnownKeywords.VirtualHost] = Uri.UnescapeDataString(uri.AbsolutePath[1..]);
}
- }
- }
- private static void AssertIsKnownKeyword(string keyword)
- {
- if (!KnownKeywords.Exists(keyword))
- {
- throw new ArgumentException($"Keyword not supported: '{keyword}'.", nameof(keyword));
+ NameValueCollection queryString = HttpUtility.ParseQueryString(uri.Query);
+
+ foreach (string remainingKeyword in queryString.AllKeys.Where(key => key != null && !KnownKeywords.Exists(key)).Cast())
+ {
+ string? value = queryString.Get(remainingKeyword);
+
+ if (value != null)
+ {
+ _settings[remainingKeyword] = value;
+ }
+ }
}
}
diff --git a/src/Connectors/src/Connectors/Redis/RedisConnectionStringBuilder.cs b/src/Connectors/src/Connectors/Redis/RedisConnectionStringBuilder.cs
index 8d791a0ebf..3b15fb52b9 100644
--- a/src/Connectors/src/Connectors/Redis/RedisConnectionStringBuilder.cs
+++ b/src/Connectors/src/Connectors/Redis/RedisConnectionStringBuilder.cs
@@ -29,14 +29,8 @@ public object? this[string keyword]
{
ArgumentException.ThrowIfNullOrWhiteSpace(keyword);
- // Allow getting unknown keyword, if it was set earlier. We don't pretend to know all valid keywords.
- if (_settings.TryGetValue(keyword, out string? value))
- {
- return value;
- }
-
- AssertIsKnownKeyword(keyword);
- return null;
+ // Allow getting unknown keyword. We don't pretend to know all valid query string parameters.
+ return _settings.GetValueOrDefault(keyword);
}
set
{
@@ -50,7 +44,7 @@ public object? this[string keyword]
}
else
{
- // Allow setting unknown keyword. We don't pretend to know all valid keywords.
+ // Allow setting unknown keyword. We don't pretend to know all valid query string parameters.
_settings[keyword] = stringValue;
}
}
@@ -120,14 +114,6 @@ private void FromConnectionString(string? connectionString)
}
}
- private static void AssertIsKnownKeyword(string keyword)
- {
- if (!KnownKeywords.Exists(keyword))
- {
- throw new ArgumentException($"Keyword not supported: '{keyword}'.", nameof(keyword));
- }
- }
-
private static class KnownKeywords
{
public const string Host = "host";
diff --git a/src/Connectors/test/Connectors.Test/MongoDb/MongoDbConnectionStringBuilderTest.cs b/src/Connectors/test/Connectors.Test/MongoDb/MongoDbConnectionStringBuilderTest.cs
index 7c10250f61..a5d339489d 100644
--- a/src/Connectors/test/Connectors.Test/MongoDb/MongoDbConnectionStringBuilderTest.cs
+++ b/src/Connectors/test/Connectors.Test/MongoDb/MongoDbConnectionStringBuilderTest.cs
@@ -82,13 +82,13 @@ public void Returns_null_when_getting_known_keyword()
}
[Fact]
- public void Throws_when_getting_unknown_keyword()
+ public void Returns_null_when_getting_unknown_keyword()
{
var builder = new MongoDbConnectionStringBuilder();
- Action action = () => _ = builder["bad"];
+ object? some = builder["some"];
- action.Should().ThrowExactly().WithMessage("Keyword not supported: 'bad'.*");
+ some.Should().BeNull();
}
[Fact]
diff --git a/src/Connectors/test/Connectors.Test/MongoDb/MongoDbConnectorTest.cs b/src/Connectors/test/Connectors.Test/MongoDb/MongoDbConnectorTest.cs
index d9935f8902..3d200dcd08 100644
--- a/src/Connectors/test/Connectors.Test/MongoDb/MongoDbConnectorTest.cs
+++ b/src/Connectors/test/Connectors.Test/MongoDb/MongoDbConnectorTest.cs
@@ -158,7 +158,7 @@ public async Task Binds_options_with_CloudFoundry_service_bindings()
MongoDbOptions optionsOne = optionsMonitor.Get("myMongoDbServiceOne");
optionsOne.ConnectionString.Should().Be(
- "mongodb://csb0230eada-2354-4c73-b3e4-8a1aaa996894:AiNtEyASbdXR5neJmTStMzKGItX2xvKuyEkcy65rviKD0ggZR19E1iVFIJ5ZAIY1xvvAiS5tOXsmACDbKDJIhQ%3D%3D@csb0230eada-2354-4c73-b3e4-8a1aaa996894.mongo.cosmos.cloud-hostname.com:10255/csb-db0230eada-2354-4c73-b3e4-8a1aaa996894?connectTimeoutMS=5000&ssl=true&replicaSet=globaldb&retrywrites=false&maxIdleTimeMS=120000&appName=@csb0230eada-2354-4c73-b3e4-8a1aaa996894@");
+ "mongodb://csb0230eada-2354-4c73-b3e4-8a1aaa996894:AiNtEyASbdXR5neJmTStMzKGItX2xvKuyEkcy65rviKD0ggZR19E1iVFIJ5ZAIY1xvvAiS5tOXsmACDbKDJIhQ%3D%3D@csb0230eada-2354-4c73-b3e4-8a1aaa996894.mongo.cosmos.cloud-hostname.com:10255/csb-db0230eada-2354-4c73-b3e4-8a1aaa996894?ssl=true&replicaSet=globaldb&retrywrites=false&maxIdleTimeMS=120000&appName=@csb0230eada-2354-4c73-b3e4-8a1aaa996894@");
optionsOne.Database.Should().Be("csb-db0230eada-2354-4c73-b3e4-8a1aaa996894");
diff --git a/src/Connectors/test/Connectors.Test/RabbitMQ/RabbitMQConnectionStringBuilderTest.cs b/src/Connectors/test/Connectors.Test/RabbitMQ/RabbitMQConnectionStringBuilderTest.cs
index a82c343c9a..4dc3cb7800 100644
--- a/src/Connectors/test/Connectors.Test/RabbitMQ/RabbitMQConnectionStringBuilderTest.cs
+++ b/src/Connectors/test/Connectors.Test/RabbitMQ/RabbitMQConnectionStringBuilderTest.cs
@@ -41,6 +41,21 @@ public void Decodes_properties_with_special_characters()
builder["virtualHost"].Should().Be("my virtual= host");
}
+ [Fact]
+ public void Preserves_query_string_parameters_when_setting_URL()
+ {
+ var builder = new RabbitMQConnectionStringBuilder
+ {
+ ConnectionString = "amqps://localhost:999/virtual-host-1?first=one&second=two"
+ };
+
+ const string url = "amqps://localhost:999/virtual-host-1?first=one&second=number2";
+ builder["url"] = url;
+
+ builder.ConnectionString.Should().Be("amqps://localhost:999/virtual-host-1?first=one&second=number2");
+ builder["url"].Should().Be(builder.ConnectionString);
+ }
+
[Fact]
public void Returns_null_when_getting_known_keyword()
{
@@ -52,22 +67,24 @@ public void Returns_null_when_getting_known_keyword()
}
[Fact]
- public void Throws_when_getting_unknown_keyword()
+ public void Returns_null_when_getting_unknown_keyword()
{
var builder = new RabbitMQConnectionStringBuilder();
- Action action = () => _ = builder["bad"];
+ object? some = builder["some"];
- action.Should().ThrowExactly().WithMessage("Keyword not supported: 'bad'.*");
+ some.Should().BeNull();
}
[Fact]
- public void Throws_when_setting_unknown_keyword()
+ public void Can_get_unknown_keyword_that_was_set_earlier()
{
- var builder = new RabbitMQConnectionStringBuilder();
-
- Action action = () => builder["bad"] = "some";
+ var builder = new RabbitMQConnectionStringBuilder
+ {
+ ["some"] = "other"
+ };
- action.Should().ThrowExactly().WithMessage("Keyword not supported: 'bad'.*");
+ object? value = builder["some"];
+ value.Should().Be("other");
}
}
diff --git a/src/Connectors/test/Connectors.Test/RabbitMQ/RabbitMQConnectorTest.cs b/src/Connectors/test/Connectors.Test/RabbitMQ/RabbitMQConnectorTest.cs
index ebca84c1fe..5ec987837a 100644
--- a/src/Connectors/test/Connectors.Test/RabbitMQ/RabbitMQConnectorTest.cs
+++ b/src/Connectors/test/Connectors.Test/RabbitMQ/RabbitMQConnectorTest.cs
@@ -190,8 +190,8 @@ public async Task Binds_options_without_service_bindings()
{
var appSettings = new Dictionary
{
- ["Steeltoe:Client:RabbitMQ:myRabbitMQServiceOne:ConnectionString"] = "amqp://user1:pass1@host1:5672/virtual-host-1",
- ["Steeltoe:Client:RabbitMQ:myRabbitMQServiceTwo:ConnectionString"] = "amqps://user2:pass2@host2:5672/virtual-host-2"
+ ["Steeltoe:Client:RabbitMQ:myRabbitMQServiceOne:ConnectionString"] = "amqp://user1:pass1@host1:5672/virtual-host-1?heartbeat=5",
+ ["Steeltoe:Client:RabbitMQ:myRabbitMQServiceTwo:ConnectionString"] = "amqps://user2:pass2@host2:5672/virtual-host-2?connection_timeout=5000"
};
WebApplicationBuilder builder = TestWebApplicationBuilderFactory.Create();
@@ -203,10 +203,10 @@ public async Task Binds_options_without_service_bindings()
var optionsSnapshot = scope.ServiceProvider.GetRequiredService>();
RabbitMQOptions optionsOne = optionsSnapshot.Get("myRabbitMQServiceOne");
- optionsOne.ConnectionString.Should().Be("amqp://user1:pass1@host1:5672/virtual-host-1");
+ optionsOne.ConnectionString.Should().Be("amqp://user1:pass1@host1:5672/virtual-host-1?heartbeat=5");
RabbitMQOptions optionsTwo = optionsSnapshot.Get("myRabbitMQServiceTwo");
- optionsTwo.ConnectionString.Should().Be("amqps://user2:pass2@host2:5672/virtual-host-2");
+ optionsTwo.ConnectionString.Should().Be("amqps://user2:pass2@host2:5672/virtual-host-2?connection_timeout=5000");
}
[Fact]
@@ -214,7 +214,7 @@ public async Task Binds_options_with_CloudFoundry_service_bindings()
{
var appSettings = new Dictionary
{
- ["Steeltoe:Client:RabbitMQ:myRabbitMQServiceOne:ConnectionString"] = "amqps://user:pass@localhost:5672"
+ ["Steeltoe:Client:RabbitMQ:myRabbitMQServiceOne:ConnectionString"] = "amqps://user:pass@localhost:5672?connection_timeout=5000&heartbeat=5"
};
WebApplicationBuilder builder = TestWebApplicationBuilderFactory.Create();
@@ -228,7 +228,7 @@ public async Task Binds_options_with_CloudFoundry_service_bindings()
RabbitMQOptions optionsOne = optionsMonitor.Get("myRabbitMQServiceOne");
optionsOne.ConnectionString.Should().Be(
- "amqp://d2fd2c9d-ef84-406b-8401-f2ffacaafda6:AqntL6IwehKOGssE51psrJYd@q-s0.rabbitmq-server.benicia-services-subnet.service-instance-377d9d72-e951-4a1c-82e8-99c3c4933368.bosh:5672/377d9d72-e951-4a1c-82e8-99c3c4933368");
+ "amqp://d2fd2c9d-ef84-406b-8401-f2ffacaafda6:AqntL6IwehKOGssE51psrJYd@q-s0.rabbitmq-server.benicia-services-subnet.service-instance-377d9d72-e951-4a1c-82e8-99c3c4933368.bosh:5672/377d9d72-e951-4a1c-82e8-99c3c4933368?connection_timeout=5000&heartbeat=5");
RabbitMQOptions optionsTwo = optionsMonitor.Get("myRabbitMQServiceTwo");
diff --git a/src/Connectors/test/Connectors.Test/Redis/RedisConnectionStringBuilderTest.cs b/src/Connectors/test/Connectors.Test/Redis/RedisConnectionStringBuilderTest.cs
index f04440d3ed..e6dfa388fc 100644
--- a/src/Connectors/test/Connectors.Test/Redis/RedisConnectionStringBuilderTest.cs
+++ b/src/Connectors/test/Connectors.Test/Redis/RedisConnectionStringBuilderTest.cs
@@ -46,13 +46,13 @@ public void Returns_null_when_getting_known_keyword()
}
[Fact]
- public void Throws_when_getting_unknown_keyword()
+ public void Returns_null_when_getting_unknown_keyword()
{
var builder = new RedisConnectionStringBuilder();
- Action action = () => _ = builder["bad"];
+ object? some = builder["some"];
- action.Should().ThrowExactly().WithMessage("Keyword not supported: 'bad'.*");
+ some.Should().BeNull();
}
[Fact]
From bf8abadd9361b29b2af1e895dab1fdd07b86b5f0 Mon Sep 17 00:00:00 2001
From: Bart Koelman <104792814+bart-vmware@users.noreply.github.com>
Date: Wed, 22 Apr 2026 16:22:44 +0200
Subject: [PATCH 5/7] Refactor to allow multiple
CloudFoundryServiceBindingConfigurationSources in configuration, each scoped
to a subset of post-processors
---
.../HostBuilderExtensionsTest.cs | 2 +-
.../src/CloudFoundry/PublicAPI.Unshipped.txt | 13 +
...oundryServiceBindingConfigurationSource.cs | 11 +-
.../CloudFoundryServiceBrokerTypes.cs | 25 ++
.../ConfigurationBuilderExtensions.cs | 113 ++++++--
.../ConfigurationBuilderExtensions.cs | 2 +-
...ServiceBindingConfigurationProviderTest.cs | 6 +-
.../ConfigurationBuilderExtensionsTest.cs | 11 +
.../ConnectorConfigureOptionsBuilder.cs | 4 +
.../src/Connectors/ConnectorConfigurer.cs | 12 +-
.../CosmosDbConfigurationBuilderExtensions.cs | 10 +-
.../MongoDbConfigurationBuilderExtensions.cs | 18 +-
...MongoDbHostApplicationBuilderExtensions.cs | 9 +-
.../MySqlConfigurationBuilderExtensions.cs | 18 +-
.../MySqlHostApplicationBuilderExtensions.cs | 9 +-
...ostgreSqlConfigurationBuilderExtensions.cs | 22 +-
...tgreSqlHostApplicationBuilderExtensions.cs | 10 +-
.../RabbitMQConfigurationBuilderExtensions.cs | 20 +-
...abbitMQHostApplicationBuilderExtensions.cs | 9 +-
.../RedisConfigurationBuilderExtensions.cs | 18 +-
.../RedisHostApplicationBuilderExtensions.cs | 9 +-
...SqlServerConfigurationBuilderExtensions.cs | 21 +-
...lServerHostApplicationBuilderExtensions.cs | 9 +-
.../test/Connectors.Test/CustomBrokerTests.cs | 266 ++++++++++++++++++
.../MongoDb/MongoDbConnectorTest.cs | 6 +-
.../MySqlConnector/MySqlConnectorTest.cs | 14 +-
.../MySql/Oracle/MySqlConnectorTest.cs | 14 +-
.../PostgreSql/PostgreSqlConnectorTest.cs | 112 +-------
.../RabbitMQ/RabbitMQConnectorTest.cs | 6 +-
.../Redis/RedisConnectorTest.cs | 6 +-
.../MicrosoftData/SqlServerConnectorTest.cs | 14 +-
.../SystemData/SqlServerConnectorTest.cs | 14 +-
...qlDbContextOptionsBuilderExtensionsTest.cs | 4 +-
...qlDbContextOptionsBuilderExtensionsTest.cs | 6 +-
...erDbContextOptionsBuilderExtensionsTest.cs | 4 +-
.../test/Eureka.Test/CloudFoundryTest.cs | 10 +-
.../RegisterMultipleDiscoveryClientsTest.cs | 11 +-
.../PostConfigureJwtBearerOptionsTest.cs | 4 +-
.../PostConfigureOpenIdConnectOptionsTest.cs | 2 +-
39 files changed, 648 insertions(+), 226 deletions(-)
create mode 100644 src/Configuration/src/CloudFoundry/ServiceBindings/CloudFoundryServiceBrokerTypes.cs
create mode 100644 src/Connectors/test/Connectors.Test/CustomBrokerTests.cs
diff --git a/src/Bootstrap/test/AutoConfiguration.Test/HostBuilderExtensionsTest.cs b/src/Bootstrap/test/AutoConfiguration.Test/HostBuilderExtensionsTest.cs
index 8dda994220..158756d68a 100644
--- a/src/Bootstrap/test/AutoConfiguration.Test/HostBuilderExtensionsTest.cs
+++ b/src/Bootstrap/test/AutoConfiguration.Test/HostBuilderExtensionsTest.cs
@@ -308,7 +308,7 @@ private static void AssertConnectorsAreAutowired(HostWrapper hostWrapper)
var configuration = hostWrapper.Services.GetRequiredService();
configuration.EnumerateProviders().Should().NotBeEmpty();
- configuration.EnumerateProviders().Should().ContainSingle();
+ configuration.EnumerateProviders().Should().NotBeEmpty();
hostWrapper.Services.GetService>().Should().NotBeNull();
hostWrapper.Services.GetService>().Should().NotBeNull();
diff --git a/src/Configuration/src/CloudFoundry/PublicAPI.Unshipped.txt b/src/Configuration/src/CloudFoundry/PublicAPI.Unshipped.txt
index 7dc5c58110..f953312ae5 100644
--- a/src/Configuration/src/CloudFoundry/PublicAPI.Unshipped.txt
+++ b/src/Configuration/src/CloudFoundry/PublicAPI.Unshipped.txt
@@ -1 +1,14 @@
#nullable enable
+static Steeltoe.Configuration.CloudFoundry.ServiceBindings.ConfigurationBuilderExtensions.AddCloudFoundryServiceBindings(this Microsoft.Extensions.Configuration.IConfigurationBuilder! builder, Steeltoe.Configuration.CloudFoundry.ServiceBindings.CloudFoundryServiceBrokerTypes brokerTypes) -> Microsoft.Extensions.Configuration.IConfigurationBuilder!
+static Steeltoe.Configuration.CloudFoundry.ServiceBindings.ConfigurationBuilderExtensions.AddCloudFoundryServiceBindings(this Microsoft.Extensions.Configuration.IConfigurationBuilder! builder, System.Predicate! ignoreKeyPredicate, Steeltoe.Configuration.CloudFoundry.ServiceBindings.IServiceBindingsReader? serviceBindingsReader, Steeltoe.Configuration.CloudFoundry.ServiceBindings.CloudFoundryServiceBrokerTypes brokerTypes, Microsoft.Extensions.Logging.ILoggerFactory! loggerFactory) -> Microsoft.Extensions.Configuration.IConfigurationBuilder!
+Steeltoe.Configuration.CloudFoundry.ServiceBindings.CloudFoundryServiceBrokerTypes
+Steeltoe.Configuration.CloudFoundry.ServiceBindings.CloudFoundryServiceBrokerTypes.All = Steeltoe.Configuration.CloudFoundry.ServiceBindings.CloudFoundryServiceBrokerTypes.Eureka | Steeltoe.Configuration.CloudFoundry.ServiceBindings.CloudFoundryServiceBrokerTypes.Identity | Steeltoe.Configuration.CloudFoundry.ServiceBindings.CloudFoundryServiceBrokerTypes.MongoDb | Steeltoe.Configuration.CloudFoundry.ServiceBindings.CloudFoundryServiceBrokerTypes.MySql | Steeltoe.Configuration.CloudFoundry.ServiceBindings.CloudFoundryServiceBrokerTypes.PostgreSql | Steeltoe.Configuration.CloudFoundry.ServiceBindings.CloudFoundryServiceBrokerTypes.RabbitMQ | Steeltoe.Configuration.CloudFoundry.ServiceBindings.CloudFoundryServiceBrokerTypes.Redis | Steeltoe.Configuration.CloudFoundry.ServiceBindings.CloudFoundryServiceBrokerTypes.SqlServer -> Steeltoe.Configuration.CloudFoundry.ServiceBindings.CloudFoundryServiceBrokerTypes
+Steeltoe.Configuration.CloudFoundry.ServiceBindings.CloudFoundryServiceBrokerTypes.Eureka = 1 -> Steeltoe.Configuration.CloudFoundry.ServiceBindings.CloudFoundryServiceBrokerTypes
+Steeltoe.Configuration.CloudFoundry.ServiceBindings.CloudFoundryServiceBrokerTypes.Identity = 2 -> Steeltoe.Configuration.CloudFoundry.ServiceBindings.CloudFoundryServiceBrokerTypes
+Steeltoe.Configuration.CloudFoundry.ServiceBindings.CloudFoundryServiceBrokerTypes.MongoDb = 4 -> Steeltoe.Configuration.CloudFoundry.ServiceBindings.CloudFoundryServiceBrokerTypes
+Steeltoe.Configuration.CloudFoundry.ServiceBindings.CloudFoundryServiceBrokerTypes.MySql = 8 -> Steeltoe.Configuration.CloudFoundry.ServiceBindings.CloudFoundryServiceBrokerTypes
+Steeltoe.Configuration.CloudFoundry.ServiceBindings.CloudFoundryServiceBrokerTypes.None = 0 -> Steeltoe.Configuration.CloudFoundry.ServiceBindings.CloudFoundryServiceBrokerTypes
+Steeltoe.Configuration.CloudFoundry.ServiceBindings.CloudFoundryServiceBrokerTypes.PostgreSql = 16 -> Steeltoe.Configuration.CloudFoundry.ServiceBindings.CloudFoundryServiceBrokerTypes
+Steeltoe.Configuration.CloudFoundry.ServiceBindings.CloudFoundryServiceBrokerTypes.RabbitMQ = 32 -> Steeltoe.Configuration.CloudFoundry.ServiceBindings.CloudFoundryServiceBrokerTypes
+Steeltoe.Configuration.CloudFoundry.ServiceBindings.CloudFoundryServiceBrokerTypes.Redis = 64 -> Steeltoe.Configuration.CloudFoundry.ServiceBindings.CloudFoundryServiceBrokerTypes
+Steeltoe.Configuration.CloudFoundry.ServiceBindings.CloudFoundryServiceBrokerTypes.SqlServer = 128 -> Steeltoe.Configuration.CloudFoundry.ServiceBindings.CloudFoundryServiceBrokerTypes
diff --git a/src/Configuration/src/CloudFoundry/ServiceBindings/CloudFoundryServiceBindingConfigurationSource.cs b/src/Configuration/src/CloudFoundry/ServiceBindings/CloudFoundryServiceBindingConfigurationSource.cs
index ade7b18591..049734ab5b 100644
--- a/src/Configuration/src/CloudFoundry/ServiceBindings/CloudFoundryServiceBindingConfigurationSource.cs
+++ b/src/Configuration/src/CloudFoundry/ServiceBindings/CloudFoundryServiceBindingConfigurationSource.cs
@@ -2,19 +2,23 @@
// The .NET Foundation licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information.
+using System.Diagnostics;
using Microsoft.Extensions.Configuration;
namespace Steeltoe.Configuration.CloudFoundry.ServiceBindings;
+[DebuggerDisplay("{DebuggerToString(),nq}")]
internal sealed class CloudFoundryServiceBindingConfigurationSource : PostProcessorConfigurationSource, IConfigurationSource
{
private readonly IServiceBindingsReader _serviceBindingsReader;
+ private readonly CloudFoundryServiceBrokerTypes _brokerTypes;
- public CloudFoundryServiceBindingConfigurationSource(IServiceBindingsReader serviceBindingsReader)
+ public CloudFoundryServiceBindingConfigurationSource(IServiceBindingsReader serviceBindingsReader, CloudFoundryServiceBrokerTypes brokerTypes)
{
ArgumentNullException.ThrowIfNull(serviceBindingsReader);
_serviceBindingsReader = serviceBindingsReader;
+ _brokerTypes = brokerTypes;
}
public IConfigurationProvider Build(IConfigurationBuilder builder)
@@ -24,4 +28,9 @@ public IConfigurationProvider Build(IConfigurationBuilder builder)
CaptureConfigurationBuilder(builder);
return new CloudFoundryServiceBindingConfigurationProvider(this, _serviceBindingsReader);
}
+
+ private string DebuggerToString()
+ {
+ return $"{GetType().FullName} ({_brokerTypes})";
+ }
}
diff --git a/src/Configuration/src/CloudFoundry/ServiceBindings/CloudFoundryServiceBrokerTypes.cs b/src/Configuration/src/CloudFoundry/ServiceBindings/CloudFoundryServiceBrokerTypes.cs
new file mode 100644
index 0000000000..3d0dbf764d
--- /dev/null
+++ b/src/Configuration/src/CloudFoundry/ServiceBindings/CloudFoundryServiceBrokerTypes.cs
@@ -0,0 +1,25 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the Apache 2.0 License.
+// See the LICENSE file in the project root for more information.
+
+namespace Steeltoe.Configuration.CloudFoundry.ServiceBindings;
+
+///
+/// Lists the built-in Cloud Foundry service brokers.
+///
+[Flags]
+public enum CloudFoundryServiceBrokerTypes
+{
+ None = 0x0,
+
+ Eureka = 0x1,
+ Identity = 0x2,
+ MongoDb = 0x4,
+ MySql = 0x8,
+ PostgreSql = 0x10,
+ RabbitMQ = 0x20,
+ Redis = 0x40,
+ SqlServer = 0x80,
+
+ All = Eureka | Identity | MongoDb | MySql | PostgreSql | RabbitMQ | Redis | SqlServer
+}
diff --git a/src/Configuration/src/CloudFoundry/ServiceBindings/ConfigurationBuilderExtensions.cs b/src/Configuration/src/CloudFoundry/ServiceBindings/ConfigurationBuilderExtensions.cs
index a7756115f9..d5b880eeb1 100644
--- a/src/Configuration/src/CloudFoundry/ServiceBindings/ConfigurationBuilderExtensions.cs
+++ b/src/Configuration/src/CloudFoundry/ServiceBindings/ConfigurationBuilderExtensions.cs
@@ -29,7 +29,24 @@ public static class ConfigurationBuilderExtensions
///
public static IConfigurationBuilder AddCloudFoundryServiceBindings(this IConfigurationBuilder builder)
{
- return builder.AddCloudFoundryServiceBindings(DefaultIgnoreKeyPredicate, DefaultReader, NullLoggerFactory.Instance);
+ return builder.AddCloudFoundryServiceBindings(DefaultIgnoreKeyPredicate, null, CloudFoundryServiceBrokerTypes.All, NullLoggerFactory.Instance);
+ }
+
+ ///
+ /// Adds CloudFoundry service bindings from the JSON provided by the specified reader.
+ ///
+ ///
+ /// The to add configuration to.
+ ///
+ ///
+ /// The set of broker types to read service bindings for.
+ ///
+ ///
+ /// The incoming so that additional calls can be chained.
+ ///
+ public static IConfigurationBuilder AddCloudFoundryServiceBindings(this IConfigurationBuilder builder, CloudFoundryServiceBrokerTypes brokerTypes)
+ {
+ return builder.AddCloudFoundryServiceBindings(DefaultIgnoreKeyPredicate, null, brokerTypes, NullLoggerFactory.Instance);
}
///
@@ -46,7 +63,8 @@ public static IConfigurationBuilder AddCloudFoundryServiceBindings(this IConfigu
///
public static IConfigurationBuilder AddCloudFoundryServiceBindings(this IConfigurationBuilder builder, IServiceBindingsReader serviceBindingsReader)
{
- return builder.AddCloudFoundryServiceBindings(DefaultIgnoreKeyPredicate, serviceBindingsReader, NullLoggerFactory.Instance);
+ return builder.AddCloudFoundryServiceBindings(DefaultIgnoreKeyPredicate, serviceBindingsReader, CloudFoundryServiceBrokerTypes.All,
+ NullLoggerFactory.Instance);
}
///
@@ -56,7 +74,7 @@ public static IConfigurationBuilder AddCloudFoundryServiceBindings(this IConfigu
/// The to add configuration to.
///
///
- /// A predicate which is called before adding a key to the configuration. If it returns false, the key will be ignored.
+ /// A predicate that is called before adding a key to the configuration. If it returns false, the key will be ignored.
///
///
/// The source to read JSON service bindings from.
@@ -69,15 +87,41 @@ public static IConfigurationBuilder AddCloudFoundryServiceBindings(this IConfigu
///
public static IConfigurationBuilder AddCloudFoundryServiceBindings(this IConfigurationBuilder builder, Predicate ignoreKeyPredicate,
IServiceBindingsReader serviceBindingsReader, ILoggerFactory loggerFactory)
+ {
+ return AddCloudFoundryServiceBindings(builder, ignoreKeyPredicate, serviceBindingsReader, CloudFoundryServiceBrokerTypes.All, loggerFactory);
+ }
+
+ ///
+ /// Adds CloudFoundry service bindings from the JSON provided by the specified reader.
+ ///
+ ///
+ /// The to add configuration to.
+ ///
+ ///
+ /// A predicate that is called before adding a key to the configuration. If it returns false, the key will be ignored.
+ ///
+ ///
+ /// The source to read JSON service bindings from.
+ ///
+ ///
+ /// The set of broker types to read service bindings for.
+ ///
+ ///
+ /// Used for internal logging. Pass to disable logging.
+ ///
+ ///
+ /// The incoming so that additional calls can be chained.
+ ///
+ public static IConfigurationBuilder AddCloudFoundryServiceBindings(this IConfigurationBuilder builder, Predicate ignoreKeyPredicate,
+ IServiceBindingsReader? serviceBindingsReader, CloudFoundryServiceBrokerTypes brokerTypes, ILoggerFactory loggerFactory)
{
ArgumentNullException.ThrowIfNull(builder);
ArgumentNullException.ThrowIfNull(ignoreKeyPredicate);
- ArgumentNullException.ThrowIfNull(serviceBindingsReader);
ArgumentNullException.ThrowIfNull(loggerFactory);
- if (!builder.EnumerateSources().Any())
+ if (brokerTypes != CloudFoundryServiceBrokerTypes.None)
{
- var source = new CloudFoundryServiceBindingConfigurationSource(serviceBindingsReader)
+ var source = new CloudFoundryServiceBindingConfigurationSource(serviceBindingsReader ?? DefaultReader, brokerTypes)
{
IgnoreKeyPredicate = ignoreKeyPredicate
};
@@ -86,25 +130,56 @@ public static IConfigurationBuilder AddCloudFoundryServiceBindings(this IConfigu
// WebApplicationBuilder immediately builds the configuration provider and loads it, which executes the post-processors.
// Therefore, adding post-processors afterward is a no-op.
- RegisterPostProcessors(source, loggerFactory);
+ RegisterPostProcessors(source, brokerTypes, loggerFactory);
builder.Add(source);
}
return builder;
}
- private static void RegisterPostProcessors(CloudFoundryServiceBindingConfigurationSource source, ILoggerFactory loggerFactory)
+ private static void RegisterPostProcessors(CloudFoundryServiceBindingConfigurationSource source, CloudFoundryServiceBrokerTypes brokerTypes,
+ ILoggerFactory loggerFactory)
{
- ILogger eurekaLogger = loggerFactory.CreateLogger();
- ILogger identityLogger = loggerFactory.CreateLogger();
-
- source.RegisterPostProcessor(new EurekaCloudFoundryPostProcessor(eurekaLogger));
- source.RegisterPostProcessor(new IdentityCloudFoundryPostProcessor(identityLogger));
- source.RegisterPostProcessor(new MongoDbCloudFoundryPostProcessor());
- source.RegisterPostProcessor(new MySqlCloudFoundryPostProcessor());
- source.RegisterPostProcessor(new PostgreSqlCloudFoundryPostProcessor());
- source.RegisterPostProcessor(new RabbitMQCloudFoundryPostProcessor());
- source.RegisterPostProcessor(new RedisCloudFoundryPostProcessor());
- source.RegisterPostProcessor(new SqlServerCloudFoundryPostProcessor());
+ if (brokerTypes.HasFlag(CloudFoundryServiceBrokerTypes.Eureka))
+ {
+ ILogger eurekaLogger = loggerFactory.CreateLogger();
+ source.RegisterPostProcessor(new EurekaCloudFoundryPostProcessor(eurekaLogger));
+ }
+
+ if (brokerTypes.HasFlag(CloudFoundryServiceBrokerTypes.Identity))
+ {
+ ILogger identityLogger = loggerFactory.CreateLogger();
+ source.RegisterPostProcessor(new IdentityCloudFoundryPostProcessor(identityLogger));
+ }
+
+ if (brokerTypes.HasFlag(CloudFoundryServiceBrokerTypes.MongoDb))
+ {
+ source.RegisterPostProcessor(new MongoDbCloudFoundryPostProcessor());
+ }
+
+ if (brokerTypes.HasFlag(CloudFoundryServiceBrokerTypes.MySql))
+ {
+ source.RegisterPostProcessor(new MySqlCloudFoundryPostProcessor());
+ }
+
+ if (brokerTypes.HasFlag(CloudFoundryServiceBrokerTypes.PostgreSql))
+ {
+ source.RegisterPostProcessor(new PostgreSqlCloudFoundryPostProcessor());
+ }
+
+ if (brokerTypes.HasFlag(CloudFoundryServiceBrokerTypes.RabbitMQ))
+ {
+ source.RegisterPostProcessor(new RabbitMQCloudFoundryPostProcessor());
+ }
+
+ if (brokerTypes.HasFlag(CloudFoundryServiceBrokerTypes.Redis))
+ {
+ source.RegisterPostProcessor(new RedisCloudFoundryPostProcessor());
+ }
+
+ if (brokerTypes.HasFlag(CloudFoundryServiceBrokerTypes.SqlServer))
+ {
+ source.RegisterPostProcessor(new SqlServerCloudFoundryPostProcessor());
+ }
}
}
diff --git a/src/Configuration/src/Kubernetes.ServiceBindings/ConfigurationBuilderExtensions.cs b/src/Configuration/src/Kubernetes.ServiceBindings/ConfigurationBuilderExtensions.cs
index c946f40952..3b0ffa3cd8 100644
--- a/src/Configuration/src/Kubernetes.ServiceBindings/ConfigurationBuilderExtensions.cs
+++ b/src/Configuration/src/Kubernetes.ServiceBindings/ConfigurationBuilderExtensions.cs
@@ -68,7 +68,7 @@ public static IConfigurationBuilder AddKubernetesServiceBindings(this IConfigura
/// Whether the configuration should be reloaded if the files are changed, added or removed.
///
///
- /// A predicate which is called before adding a key to the configuration. If it returns false, the key will be ignored.
+ /// A predicate that is called before adding a key to the configuration. If it returns false, the key will be ignored.
///
///
/// The source to read Kubernetes secret files on disk from.
diff --git a/src/Configuration/test/CloudFoundry.Test/ServiceBindings/CloudFoundryServiceBindingConfigurationProviderTest.cs b/src/Configuration/test/CloudFoundry.Test/ServiceBindings/CloudFoundryServiceBindingConfigurationProviderTest.cs
index 91aa24f7fd..ce973ec42f 100644
--- a/src/Configuration/test/CloudFoundry.Test/ServiceBindings/CloudFoundryServiceBindingConfigurationProviderTest.cs
+++ b/src/Configuration/test/CloudFoundry.Test/ServiceBindings/CloudFoundryServiceBindingConfigurationProviderTest.cs
@@ -118,7 +118,7 @@ public void PostProcessors_OnByDefault()
var postProcessor = new TestPostProcessor();
var reader = new StringServiceBindingsReader(VcapServicesJson);
- var source = new CloudFoundryServiceBindingConfigurationSource(reader);
+ var source = new CloudFoundryServiceBindingConfigurationSource(reader, CloudFoundryServiceBrokerTypes.All);
source.RegisterPostProcessor(postProcessor);
var builder = new ConfigurationBuilder();
@@ -137,7 +137,7 @@ public void Build_CapturesParentConfiguration()
};
var reader = new StringServiceBindingsReader(string.Empty);
- var source = new CloudFoundryServiceBindingConfigurationSource(reader);
+ var source = new CloudFoundryServiceBindingConfigurationSource(reader, CloudFoundryServiceBrokerTypes.All);
var builder = new ConfigurationBuilder();
builder.Add(source);
@@ -153,7 +153,7 @@ public void Build_CapturesParentConfiguration()
public void Build_LoadsServiceBindings()
{
var reader = new StringServiceBindingsReader(VcapServicesJson);
- var source = new CloudFoundryServiceBindingConfigurationSource(reader);
+ var source = new CloudFoundryServiceBindingConfigurationSource(reader, CloudFoundryServiceBrokerTypes.All);
var builder = new ConfigurationBuilder();
builder.Add(source);
diff --git a/src/Configuration/test/CloudFoundry.Test/ServiceBindings/ConfigurationBuilderExtensionsTest.cs b/src/Configuration/test/CloudFoundry.Test/ServiceBindings/ConfigurationBuilderExtensionsTest.cs
index 0511f2e41b..5188ad19ad 100644
--- a/src/Configuration/test/CloudFoundry.Test/ServiceBindings/ConfigurationBuilderExtensionsTest.cs
+++ b/src/Configuration/test/CloudFoundry.Test/ServiceBindings/ConfigurationBuilderExtensionsTest.cs
@@ -57,6 +57,17 @@ public void AddCloudFoundryServiceBindings_RegistersProcessors()
source.PostProcessors.Should().NotBeEmpty();
}
+ [Fact]
+ public void AddCloudFoundryServiceBindings_RegistersSubsetOfProcessors()
+ {
+ var builder = new ConfigurationBuilder();
+ builder.AddCloudFoundryServiceBindings(CloudFoundryServiceBrokerTypes.PostgreSql | CloudFoundryServiceBrokerTypes.MySql);
+
+ builder.Sources.Should().ContainSingle();
+ CloudFoundryServiceBindingConfigurationSource source = builder.Sources[0].Should().BeOfType().Subject;
+ source.PostProcessors.Should().HaveCount(2);
+ }
+
[Fact]
public void AddCloudFoundryServiceBindings_EnvironmentVariableSet_LoadsServiceBindings()
{
diff --git a/src/Connectors/src/Connectors/ConnectorConfigureOptionsBuilder.cs b/src/Connectors/src/Connectors/ConnectorConfigureOptionsBuilder.cs
index 746fe5617e..ce887382a1 100644
--- a/src/Connectors/src/Connectors/ConnectorConfigureOptionsBuilder.cs
+++ b/src/Connectors/src/Connectors/ConnectorConfigureOptionsBuilder.cs
@@ -2,10 +2,14 @@
// The .NET Foundation licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information.
+using Steeltoe.Configuration.CloudFoundry.ServiceBindings;
+
namespace Steeltoe.Connectors;
public sealed class ConnectorConfigureOptionsBuilder
{
+ internal CloudFoundryServiceBrokerTypes CloudFoundryBrokerTypes { get; set; }
+
///
/// Gets or sets a value indicating whether connection string changes are detected while the application is running. This is false by default to
/// optimize startup performance. When set to true, existing configuration providers may get reloaded multiple times, potentially resulting in
diff --git a/src/Connectors/src/Connectors/ConnectorConfigurer.cs b/src/Connectors/src/Connectors/ConnectorConfigurer.cs
index ba77bbf605..5b5c489be1 100644
--- a/src/Connectors/src/Connectors/ConnectorConfigurer.cs
+++ b/src/Connectors/src/Connectors/ConnectorConfigurer.cs
@@ -3,26 +3,30 @@
// See the LICENSE file in the project root for more information.
using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Logging;
using Steeltoe.Configuration;
using Steeltoe.Configuration.CloudFoundry.ServiceBindings;
using Steeltoe.Configuration.Kubernetes.ServiceBindings;
+using IServiceBindingsReader = Steeltoe.Configuration.CloudFoundry.ServiceBindings.IServiceBindingsReader;
namespace Steeltoe.Connectors;
internal static class ConnectorConfigurer
{
- public static void Configure(IConfigurationBuilder builder, Action? configureAction,
- TPostProcessor connectionStringPostProcessor)
+ private static readonly Predicate DefaultIgnoreKeyPredicate = _ => false;
+
+ public static void Configure(IConfigurationBuilder builder, Action configureAction,
+ TPostProcessor connectionStringPostProcessor, IServiceBindingsReader? serviceBindingsReader, ILoggerFactory loggerFactory)
where TPostProcessor : ConnectionStringPostProcessor
{
if (!IsConfigured(builder))
{
var optionsBuilder = new ConnectorConfigureOptionsBuilder();
- configureAction?.Invoke(optionsBuilder);
+ configureAction.Invoke(optionsBuilder);
if (!optionsBuilder.SkipDefaultServiceBindings)
{
- builder.AddCloudFoundryServiceBindings();
+ builder.AddCloudFoundryServiceBindings(DefaultIgnoreKeyPredicate, serviceBindingsReader, optionsBuilder.CloudFoundryBrokerTypes, loggerFactory);
builder.AddKubernetesServiceBindings();
}
diff --git a/src/Connectors/src/Connectors/CosmosDb/CosmosDbConfigurationBuilderExtensions.cs b/src/Connectors/src/Connectors/CosmosDb/CosmosDbConfigurationBuilderExtensions.cs
index 2d5ea2513b..24bf87d6a5 100644
--- a/src/Connectors/src/Connectors/CosmosDb/CosmosDbConfigurationBuilderExtensions.cs
+++ b/src/Connectors/src/Connectors/CosmosDb/CosmosDbConfigurationBuilderExtensions.cs
@@ -3,6 +3,8 @@
// See the LICENSE file in the project root for more information.
using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Logging.Abstractions;
+using Steeltoe.Configuration.CloudFoundry.ServiceBindings;
namespace Steeltoe.Connectors.CosmosDb;
@@ -38,7 +40,13 @@ public static IConfigurationBuilder ConfigureCosmosDb(this IConfigurationBuilder
{
ArgumentNullException.ThrowIfNull(builder);
- ConnectorConfigurer.Configure(builder, configureAction, new CosmosDbConnectionStringPostProcessor());
+ Action overrideConfigureAction = options =>
+ {
+ configureAction?.Invoke(options);
+ options.CloudFoundryBrokerTypes = CloudFoundryServiceBrokerTypes.None;
+ };
+
+ ConnectorConfigurer.Configure(builder, overrideConfigureAction, new CosmosDbConnectionStringPostProcessor(), null, NullLoggerFactory.Instance);
return builder;
}
}
diff --git a/src/Connectors/src/Connectors/MongoDb/MongoDbConfigurationBuilderExtensions.cs b/src/Connectors/src/Connectors/MongoDb/MongoDbConfigurationBuilderExtensions.cs
index ef5fd61509..30e6d43a1e 100644
--- a/src/Connectors/src/Connectors/MongoDb/MongoDbConfigurationBuilderExtensions.cs
+++ b/src/Connectors/src/Connectors/MongoDb/MongoDbConfigurationBuilderExtensions.cs
@@ -3,6 +3,8 @@
// See the LICENSE file in the project root for more information.
using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Logging.Abstractions;
+using Steeltoe.Configuration.CloudFoundry.ServiceBindings;
namespace Steeltoe.Connectors.MongoDb;
@@ -35,10 +37,24 @@ public static IConfigurationBuilder ConfigureMongoDb(this IConfigurationBuilder
/// The incoming so that additional calls can be chained.
///
public static IConfigurationBuilder ConfigureMongoDb(this IConfigurationBuilder builder, Action? configureAction)
+ {
+ return ConfigureMongoDb(builder, configureAction, null);
+ }
+
+ internal static IConfigurationBuilder ConfigureMongoDb(this IConfigurationBuilder builder, Action? configureAction,
+ IServiceBindingsReader? serviceBindingsReader)
{
ArgumentNullException.ThrowIfNull(builder);
- ConnectorConfigurer.Configure(builder, configureAction, new MongoDbConnectionStringPostProcessor());
+ Action overrideConfigureAction = options =>
+ {
+ configureAction?.Invoke(options);
+ options.CloudFoundryBrokerTypes = options.SkipDefaultServiceBindings ? CloudFoundryServiceBrokerTypes.None : CloudFoundryServiceBrokerTypes.MongoDb;
+ };
+
+ ConnectorConfigurer.Configure(builder, overrideConfigureAction, new MongoDbConnectionStringPostProcessor(), serviceBindingsReader,
+ NullLoggerFactory.Instance);
+
return builder;
}
}
diff --git a/src/Connectors/src/Connectors/MongoDb/MongoDbHostApplicationBuilderExtensions.cs b/src/Connectors/src/Connectors/MongoDb/MongoDbHostApplicationBuilderExtensions.cs
index 021c8b4288..336673591f 100644
--- a/src/Connectors/src/Connectors/MongoDb/MongoDbHostApplicationBuilderExtensions.cs
+++ b/src/Connectors/src/Connectors/MongoDb/MongoDbHostApplicationBuilderExtensions.cs
@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using Microsoft.Extensions.Hosting;
+using Steeltoe.Configuration.CloudFoundry.ServiceBindings;
namespace Steeltoe.Connectors.MongoDb;
@@ -41,10 +42,16 @@ public static IHostApplicationBuilder AddMongoDb(this IHostApplicationBuilder bu
///
public static IHostApplicationBuilder AddMongoDb(this IHostApplicationBuilder builder, Action? configureAction,
Action? addAction)
+ {
+ return AddMongoDb(builder, configureAction, addAction, null);
+ }
+
+ internal static IHostApplicationBuilder AddMongoDb(this IHostApplicationBuilder builder, Action? configureAction,
+ Action? addAction, IServiceBindingsReader? serviceBindingsReader)
{
ArgumentNullException.ThrowIfNull(builder);
- builder.Configuration.ConfigureMongoDb(configureAction);
+ builder.Configuration.ConfigureMongoDb(configureAction, serviceBindingsReader);
builder.Services.AddMongoDb(builder.Configuration, addAction);
return builder;
}
diff --git a/src/Connectors/src/Connectors/MySql/MySqlConfigurationBuilderExtensions.cs b/src/Connectors/src/Connectors/MySql/MySqlConfigurationBuilderExtensions.cs
index 5eda76fffc..7e37ffe389 100644
--- a/src/Connectors/src/Connectors/MySql/MySqlConfigurationBuilderExtensions.cs
+++ b/src/Connectors/src/Connectors/MySql/MySqlConfigurationBuilderExtensions.cs
@@ -3,6 +3,8 @@
// See the LICENSE file in the project root for more information.
using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Logging.Abstractions;
+using Steeltoe.Configuration.CloudFoundry.ServiceBindings;
using Steeltoe.Connectors.MySql.DynamicTypeAccess;
namespace Steeltoe.Connectors.MySql;
@@ -20,7 +22,7 @@ public static class MySqlConfigurationBuilderExtensions
///
public static IConfigurationBuilder ConfigureMySql(this IConfigurationBuilder builder)
{
- return ConfigureMySql(builder, MySqlPackageResolver.Default);
+ return ConfigureMySql(builder, null);
}
///
@@ -37,16 +39,24 @@ public static IConfigurationBuilder ConfigureMySql(this IConfigurationBuilder bu
///
public static IConfigurationBuilder ConfigureMySql(this IConfigurationBuilder builder, Action? configureAction)
{
- return ConfigureMySql(builder, MySqlPackageResolver.Default, configureAction);
+ return ConfigureMySql(builder, MySqlPackageResolver.Default, configureAction, null);
}
internal static IConfigurationBuilder ConfigureMySql(this IConfigurationBuilder builder, MySqlPackageResolver packageResolver,
- Action? configureAction = null)
+ Action? configureAction, IServiceBindingsReader? serviceBindingsReader)
{
ArgumentNullException.ThrowIfNull(builder);
ArgumentNullException.ThrowIfNull(packageResolver);
- ConnectorConfigurer.Configure(builder, configureAction, new MySqlConnectionStringPostProcessor(packageResolver));
+ Action overrideConfigureAction = options =>
+ {
+ configureAction?.Invoke(options);
+ options.CloudFoundryBrokerTypes = options.SkipDefaultServiceBindings ? CloudFoundryServiceBrokerTypes.None : CloudFoundryServiceBrokerTypes.MySql;
+ };
+
+ ConnectorConfigurer.Configure(builder, overrideConfigureAction, new MySqlConnectionStringPostProcessor(packageResolver), serviceBindingsReader,
+ NullLoggerFactory.Instance);
+
return builder;
}
}
diff --git a/src/Connectors/src/Connectors/MySql/MySqlHostApplicationBuilderExtensions.cs b/src/Connectors/src/Connectors/MySql/MySqlHostApplicationBuilderExtensions.cs
index d5454e4b24..56f4335355 100644
--- a/src/Connectors/src/Connectors/MySql/MySqlHostApplicationBuilderExtensions.cs
+++ b/src/Connectors/src/Connectors/MySql/MySqlHostApplicationBuilderExtensions.cs
@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using Microsoft.Extensions.Hosting;
+using Steeltoe.Configuration.CloudFoundry.ServiceBindings;
using Steeltoe.Connectors.MySql.DynamicTypeAccess;
namespace Steeltoe.Connectors.MySql;
@@ -21,7 +22,7 @@ public static class MySqlHostApplicationBuilderExtensions
///
public static IHostApplicationBuilder AddMySql(this IHostApplicationBuilder builder)
{
- return AddMySql(builder, MySqlPackageResolver.Default);
+ return AddMySql(builder, null, null);
}
///
@@ -43,16 +44,16 @@ public static IHostApplicationBuilder AddMySql(this IHostApplicationBuilder buil
public static IHostApplicationBuilder AddMySql(this IHostApplicationBuilder builder, Action? configureAction,
Action? addAction)
{
- return AddMySql(builder, MySqlPackageResolver.Default, configureAction, addAction);
+ return AddMySql(builder, MySqlPackageResolver.Default, configureAction, addAction, null);
}
internal static IHostApplicationBuilder AddMySql(this IHostApplicationBuilder builder, MySqlPackageResolver packageResolver,
- Action? configureAction = null, Action? addAction = null)
+ Action? configureAction, Action? addAction, IServiceBindingsReader? serviceBindingsReader)
{
ArgumentNullException.ThrowIfNull(builder);
ArgumentNullException.ThrowIfNull(packageResolver);
- builder.Configuration.ConfigureMySql(packageResolver, configureAction);
+ builder.Configuration.ConfigureMySql(packageResolver, configureAction, serviceBindingsReader);
builder.Services.AddMySql(builder.Configuration, packageResolver, addAction);
return builder;
}
diff --git a/src/Connectors/src/Connectors/PostgreSql/PostgreSqlConfigurationBuilderExtensions.cs b/src/Connectors/src/Connectors/PostgreSql/PostgreSqlConfigurationBuilderExtensions.cs
index cff6a541be..06ee495a8f 100644
--- a/src/Connectors/src/Connectors/PostgreSql/PostgreSqlConfigurationBuilderExtensions.cs
+++ b/src/Connectors/src/Connectors/PostgreSql/PostgreSqlConfigurationBuilderExtensions.cs
@@ -3,6 +3,8 @@
// See the LICENSE file in the project root for more information.
using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Logging.Abstractions;
+using Steeltoe.Configuration.CloudFoundry.ServiceBindings;
using Steeltoe.Connectors.PostgreSql.DynamicTypeAccess;
namespace Steeltoe.Connectors.PostgreSql;
@@ -20,7 +22,7 @@ public static class PostgreSqlConfigurationBuilderExtensions
///
public static IConfigurationBuilder ConfigurePostgreSql(this IConfigurationBuilder builder)
{
- return ConfigurePostgreSql(builder, PostgreSqlPackageResolver.Default);
+ return ConfigurePostgreSql(builder, null);
}
///
@@ -37,16 +39,26 @@ public static IConfigurationBuilder ConfigurePostgreSql(this IConfigurationBuild
///
public static IConfigurationBuilder ConfigurePostgreSql(this IConfigurationBuilder builder, Action? configureAction)
{
- return ConfigurePostgreSql(builder, PostgreSqlPackageResolver.Default, configureAction);
+ return ConfigurePostgreSql(builder, PostgreSqlPackageResolver.Default, configureAction, null);
}
- private static IConfigurationBuilder ConfigurePostgreSql(this IConfigurationBuilder builder, PostgreSqlPackageResolver packageResolver,
- Action? configureAction = null)
+ internal static IConfigurationBuilder ConfigurePostgreSql(this IConfigurationBuilder builder, PostgreSqlPackageResolver packageResolver,
+ Action? configureAction, IServiceBindingsReader? serviceBindingsReader)
{
ArgumentNullException.ThrowIfNull(builder);
ArgumentNullException.ThrowIfNull(packageResolver);
- ConnectorConfigurer.Configure(builder, configureAction, new PostgreSqlConnectionStringPostProcessor(packageResolver));
+ Action overrideConfigureAction = options =>
+ {
+ configureAction?.Invoke(options);
+
+ options.CloudFoundryBrokerTypes =
+ options.SkipDefaultServiceBindings ? CloudFoundryServiceBrokerTypes.None : CloudFoundryServiceBrokerTypes.PostgreSql;
+ };
+
+ ConnectorConfigurer.Configure(builder, overrideConfigureAction, new PostgreSqlConnectionStringPostProcessor(packageResolver), serviceBindingsReader,
+ NullLoggerFactory.Instance);
+
return builder;
}
}
diff --git a/src/Connectors/src/Connectors/PostgreSql/PostgreSqlHostApplicationBuilderExtensions.cs b/src/Connectors/src/Connectors/PostgreSql/PostgreSqlHostApplicationBuilderExtensions.cs
index 76c4f70101..8f51288222 100644
--- a/src/Connectors/src/Connectors/PostgreSql/PostgreSqlHostApplicationBuilderExtensions.cs
+++ b/src/Connectors/src/Connectors/PostgreSql/PostgreSqlHostApplicationBuilderExtensions.cs
@@ -3,6 +3,8 @@
// See the LICENSE file in the project root for more information.
using Microsoft.Extensions.Hosting;
+using Steeltoe.Configuration.CloudFoundry.ServiceBindings;
+using Steeltoe.Connectors.PostgreSql.DynamicTypeAccess;
namespace Steeltoe.Connectors.PostgreSql;
@@ -41,10 +43,16 @@ public static IHostApplicationBuilder AddPostgreSql(this IHostApplicationBuilder
///
public static IHostApplicationBuilder AddPostgreSql(this IHostApplicationBuilder builder, Action? configureAction,
Action? addAction)
+ {
+ return AddPostgreSql(builder, configureAction, addAction, null);
+ }
+
+ internal static IHostApplicationBuilder AddPostgreSql(this IHostApplicationBuilder builder, Action? configureAction,
+ Action? addAction, IServiceBindingsReader? serviceBindingsReader)
{
ArgumentNullException.ThrowIfNull(builder);
- builder.Configuration.ConfigurePostgreSql(configureAction);
+ builder.Configuration.ConfigurePostgreSql(PostgreSqlPackageResolver.Default, configureAction, serviceBindingsReader);
builder.Services.AddPostgreSql(builder.Configuration, addAction);
return builder;
}
diff --git a/src/Connectors/src/Connectors/RabbitMQ/RabbitMQConfigurationBuilderExtensions.cs b/src/Connectors/src/Connectors/RabbitMQ/RabbitMQConfigurationBuilderExtensions.cs
index 41f6ecccd2..fd7f1e2b20 100644
--- a/src/Connectors/src/Connectors/RabbitMQ/RabbitMQConfigurationBuilderExtensions.cs
+++ b/src/Connectors/src/Connectors/RabbitMQ/RabbitMQConfigurationBuilderExtensions.cs
@@ -3,6 +3,8 @@
// See the LICENSE file in the project root for more information.
using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Logging.Abstractions;
+using Steeltoe.Configuration.CloudFoundry.ServiceBindings;
namespace Steeltoe.Connectors.RabbitMQ;
@@ -35,10 +37,26 @@ public static IConfigurationBuilder ConfigureRabbitMQ(this IConfigurationBuilder
/// The incoming so that additional calls can be chained.
///
public static IConfigurationBuilder ConfigureRabbitMQ(this IConfigurationBuilder builder, Action? configureAction)
+ {
+ return ConfigureRabbitMQ(builder, configureAction, null);
+ }
+
+ internal static IConfigurationBuilder ConfigureRabbitMQ(this IConfigurationBuilder builder, Action? configureAction,
+ IServiceBindingsReader? serviceBindingsReader)
{
ArgumentNullException.ThrowIfNull(builder);
- ConnectorConfigurer.Configure(builder, configureAction, new RabbitMQConnectionStringPostProcessor());
+ Action overrideConfigureAction = options =>
+ {
+ configureAction?.Invoke(options);
+
+ options.CloudFoundryBrokerTypes =
+ options.SkipDefaultServiceBindings ? CloudFoundryServiceBrokerTypes.None : CloudFoundryServiceBrokerTypes.RabbitMQ;
+ };
+
+ ConnectorConfigurer.Configure(builder, overrideConfigureAction, new RabbitMQConnectionStringPostProcessor(), serviceBindingsReader,
+ NullLoggerFactory.Instance);
+
return builder;
}
}
diff --git a/src/Connectors/src/Connectors/RabbitMQ/RabbitMQHostApplicationBuilderExtensions.cs b/src/Connectors/src/Connectors/RabbitMQ/RabbitMQHostApplicationBuilderExtensions.cs
index 23a98f46b6..9a851e8947 100644
--- a/src/Connectors/src/Connectors/RabbitMQ/RabbitMQHostApplicationBuilderExtensions.cs
+++ b/src/Connectors/src/Connectors/RabbitMQ/RabbitMQHostApplicationBuilderExtensions.cs
@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using Microsoft.Extensions.Hosting;
+using Steeltoe.Configuration.CloudFoundry.ServiceBindings;
namespace Steeltoe.Connectors.RabbitMQ;
@@ -41,10 +42,16 @@ public static IHostApplicationBuilder AddRabbitMQ(this IHostApplicationBuilder b
///
public static IHostApplicationBuilder AddRabbitMQ(this IHostApplicationBuilder builder, Action? configureAction,
Action? addAction)
+ {
+ return AddRabbitMQ(builder, configureAction, addAction, null);
+ }
+
+ internal static IHostApplicationBuilder AddRabbitMQ(this IHostApplicationBuilder builder, Action? configureAction,
+ Action? addAction, IServiceBindingsReader? serviceBindingsReader)
{
ArgumentNullException.ThrowIfNull(builder);
- builder.Configuration.ConfigureRabbitMQ(configureAction);
+ builder.Configuration.ConfigureRabbitMQ(configureAction, serviceBindingsReader);
builder.Services.AddRabbitMQ(builder.Configuration, addAction);
return builder;
}
diff --git a/src/Connectors/src/Connectors/Redis/RedisConfigurationBuilderExtensions.cs b/src/Connectors/src/Connectors/Redis/RedisConfigurationBuilderExtensions.cs
index 5fc8caf70b..f912a2f42d 100644
--- a/src/Connectors/src/Connectors/Redis/RedisConfigurationBuilderExtensions.cs
+++ b/src/Connectors/src/Connectors/Redis/RedisConfigurationBuilderExtensions.cs
@@ -3,6 +3,8 @@
// See the LICENSE file in the project root for more information.
using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Logging.Abstractions;
+using Steeltoe.Configuration.CloudFoundry.ServiceBindings;
namespace Steeltoe.Connectors.Redis;
@@ -35,10 +37,24 @@ public static IConfigurationBuilder ConfigureRedis(this IConfigurationBuilder bu
/// The incoming so that additional calls can be chained.
///
public static IConfigurationBuilder ConfigureRedis(this IConfigurationBuilder builder, Action? configureAction)
+ {
+ return ConfigureRedis(builder, configureAction, null);
+ }
+
+ internal static IConfigurationBuilder ConfigureRedis(this IConfigurationBuilder builder, Action? configureAction,
+ IServiceBindingsReader? serviceBindingsReader)
{
ArgumentNullException.ThrowIfNull(builder);
- ConnectorConfigurer.Configure(builder, configureAction, new RedisConnectionStringPostProcessor());
+ Action overrideConfigureAction = options =>
+ {
+ configureAction?.Invoke(options);
+ options.CloudFoundryBrokerTypes = options.SkipDefaultServiceBindings ? CloudFoundryServiceBrokerTypes.None : CloudFoundryServiceBrokerTypes.Redis;
+ };
+
+ ConnectorConfigurer.Configure(builder, overrideConfigureAction, new RedisConnectionStringPostProcessor(), serviceBindingsReader,
+ NullLoggerFactory.Instance);
+
return builder;
}
}
diff --git a/src/Connectors/src/Connectors/Redis/RedisHostApplicationBuilderExtensions.cs b/src/Connectors/src/Connectors/Redis/RedisHostApplicationBuilderExtensions.cs
index db17d66be3..c60d508ebb 100644
--- a/src/Connectors/src/Connectors/Redis/RedisHostApplicationBuilderExtensions.cs
+++ b/src/Connectors/src/Connectors/Redis/RedisHostApplicationBuilderExtensions.cs
@@ -4,6 +4,7 @@
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Hosting;
+using Steeltoe.Configuration.CloudFoundry.ServiceBindings;
namespace Steeltoe.Connectors.Redis;
@@ -46,10 +47,16 @@ public static IHostApplicationBuilder AddRedis(this IHostApplicationBuilder buil
///
public static IHostApplicationBuilder AddRedis(this IHostApplicationBuilder builder, Action? configureAction,
Action? addAction)
+ {
+ return AddRedis(builder, configureAction, addAction, null);
+ }
+
+ internal static IHostApplicationBuilder AddRedis(this IHostApplicationBuilder builder, Action? configureAction,
+ Action? addAction, IServiceBindingsReader? serviceBindingsReader)
{
ArgumentNullException.ThrowIfNull(builder);
- builder.Configuration.ConfigureRedis(configureAction);
+ builder.Configuration.ConfigureRedis(configureAction, serviceBindingsReader);
builder.Services.AddRedis(builder.Configuration, addAction);
return builder;
}
diff --git a/src/Connectors/src/Connectors/SqlServer/SqlServerConfigurationBuilderExtensions.cs b/src/Connectors/src/Connectors/SqlServer/SqlServerConfigurationBuilderExtensions.cs
index 8aa20df6df..a3bd5092e8 100644
--- a/src/Connectors/src/Connectors/SqlServer/SqlServerConfigurationBuilderExtensions.cs
+++ b/src/Connectors/src/Connectors/SqlServer/SqlServerConfigurationBuilderExtensions.cs
@@ -3,7 +3,10 @@
// See the LICENSE file in the project root for more information.
using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Logging.Abstractions;
+using Steeltoe.Configuration.CloudFoundry.ServiceBindings;
using Steeltoe.Connectors.SqlServer.RuntimeTypeAccess;
+using IServiceBindingsReader = Steeltoe.Configuration.CloudFoundry.ServiceBindings.IServiceBindingsReader;
namespace Steeltoe.Connectors.SqlServer;
@@ -20,7 +23,7 @@ public static class SqlServerConfigurationBuilderExtensions
///
public static IConfigurationBuilder ConfigureSqlServer(this IConfigurationBuilder builder)
{
- return ConfigureSqlServer(builder, SqlServerPackageResolver.Default);
+ return ConfigureSqlServer(builder, null);
}
///
@@ -37,16 +40,26 @@ public static IConfigurationBuilder ConfigureSqlServer(this IConfigurationBuilde
///
public static IConfigurationBuilder ConfigureSqlServer(this IConfigurationBuilder builder, Action? configureAction)
{
- return ConfigureSqlServer(builder, SqlServerPackageResolver.Default, configureAction);
+ return ConfigureSqlServer(builder, SqlServerPackageResolver.Default, configureAction, null);
}
internal static IConfigurationBuilder ConfigureSqlServer(this IConfigurationBuilder builder, SqlServerPackageResolver packageResolver,
- Action? configureAction = null)
+ Action? configureAction, IServiceBindingsReader? serviceBindingsReader)
{
ArgumentNullException.ThrowIfNull(builder);
ArgumentNullException.ThrowIfNull(packageResolver);
- ConnectorConfigurer.Configure(builder, configureAction, new SqlServerConnectionStringPostProcessor(packageResolver));
+ Action overrideConfigureAction = options =>
+ {
+ configureAction?.Invoke(options);
+
+ options.CloudFoundryBrokerTypes =
+ options.SkipDefaultServiceBindings ? CloudFoundryServiceBrokerTypes.None : CloudFoundryServiceBrokerTypes.SqlServer;
+ };
+
+ ConnectorConfigurer.Configure(builder, overrideConfigureAction, new SqlServerConnectionStringPostProcessor(packageResolver), serviceBindingsReader,
+ NullLoggerFactory.Instance);
+
return builder;
}
}
diff --git a/src/Connectors/src/Connectors/SqlServer/SqlServerHostApplicationBuilderExtensions.cs b/src/Connectors/src/Connectors/SqlServer/SqlServerHostApplicationBuilderExtensions.cs
index e47ff4a6ec..238e0c5aad 100644
--- a/src/Connectors/src/Connectors/SqlServer/SqlServerHostApplicationBuilderExtensions.cs
+++ b/src/Connectors/src/Connectors/SqlServer/SqlServerHostApplicationBuilderExtensions.cs
@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using Microsoft.Extensions.Hosting;
+using Steeltoe.Configuration.CloudFoundry.ServiceBindings;
using Steeltoe.Connectors.SqlServer.RuntimeTypeAccess;
namespace Steeltoe.Connectors.SqlServer;
@@ -21,7 +22,7 @@ public static class SqlServerHostApplicationBuilderExtensions
///
public static IHostApplicationBuilder AddSqlServer(this IHostApplicationBuilder builder)
{
- return AddSqlServer(builder, SqlServerPackageResolver.Default);
+ return AddSqlServer(builder, null, null);
}
///
@@ -43,16 +44,16 @@ public static IHostApplicationBuilder AddSqlServer(this IHostApplicationBuilder
public static IHostApplicationBuilder AddSqlServer(this IHostApplicationBuilder builder, Action? configureAction,
Action? addAction)
{
- return AddSqlServer(builder, SqlServerPackageResolver.Default, configureAction, addAction);
+ return AddSqlServer(builder, SqlServerPackageResolver.Default, configureAction, addAction, null);
}
internal static IHostApplicationBuilder AddSqlServer(this IHostApplicationBuilder builder, SqlServerPackageResolver packageResolver,
- Action? configureAction = null, Action? addAction = null)
+ Action? configureAction, Action? addAction, IServiceBindingsReader? serviceBindingsReader)
{
ArgumentNullException.ThrowIfNull(builder);
ArgumentNullException.ThrowIfNull(packageResolver);
- builder.Configuration.ConfigureSqlServer(packageResolver, configureAction);
+ builder.Configuration.ConfigureSqlServer(packageResolver, configureAction, serviceBindingsReader);
builder.Services.AddSqlServer(builder.Configuration, packageResolver, addAction);
return builder;
}
diff --git a/src/Connectors/test/Connectors.Test/CustomBrokerTests.cs b/src/Connectors/test/Connectors.Test/CustomBrokerTests.cs
new file mode 100644
index 0000000000..e30896fa1a
--- /dev/null
+++ b/src/Connectors/test/Connectors.Test/CustomBrokerTests.cs
@@ -0,0 +1,266 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the Apache 2.0 License.
+// See the LICENSE file in the project root for more information.
+
+using Microsoft.AspNetCore.Builder;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Options;
+using Steeltoe.Common.TestResources;
+using Steeltoe.Configuration.CloudFoundry;
+using Steeltoe.Configuration.CloudFoundry.ServiceBindings;
+using Steeltoe.Connectors.PostgreSql;
+using Steeltoe.Connectors.RabbitMQ;
+
+namespace Steeltoe.Connectors.Test;
+
+public sealed class CustomBrokerTests
+{
+ [Fact]
+ public async Task Binds_options_with_third_party_service_bindings()
+ {
+ var appSettings = new Dictionary
+ {
+ ["Steeltoe:Client:PostgreSql:products-db:ConnectionString"] = "Include Error Detail=true;host=localhost",
+ ["Steeltoe:Client:PostgreSql:orders-db:ConnectionString"] = "Log Parameters=true;port=9999"
+ };
+
+ var reader = new CloudFoundryMemorySettingsReader
+ {
+ ServicesJson = """
+ {
+ "custom-postgres-broker": [
+ {
+ "name": "products-db",
+ "credentials": {
+ "custom-hostname-key": "example.cloud.com",
+ "custom-port-key": 2345,
+ "custom-username-key": "products-user",
+ "custom-password-key": "products-secret",
+ "custom-database-name-key": "product-database",
+ "host": "IGNORED"
+ }
+ },
+ {
+ "name": "orders-db",
+ "credentials": {
+ "custom-hostname-key": "example.cloud.com",
+ "custom-port-key": 2345,
+ "custom-username-key": "orders-user",
+ "custom-password-key": "orders-secret",
+ "custom-database-name-key": "order-database"
+ }
+ }
+ ]
+ }
+ """
+ };
+
+ WebApplicationBuilder builder = TestWebApplicationBuilderFactory.Create();
+ builder.Configuration.AddInMemoryCollection(appSettings);
+ builder.Configuration.AddCloudFoundry(reader);
+ MapServiceBindingsForCustomPostgreSqlBroker("custom-postgres-broker");
+ builder.AddPostgreSql(options => options.SkipDefaultServiceBindings = true, null);
+ await using WebApplication app = builder.Build();
+
+ var optionsMonitor = app.Services.GetRequiredService>();
+ PostgreSqlOptions productsDbOptions = optionsMonitor.Get("products-db");
+ PostgreSqlOptions ordersDbOptions = optionsMonitor.Get("orders-db");
+
+ ExtractConnectionStringParameters(productsDbOptions.ConnectionString).Should().BeEquivalentTo(new List
+ {
+ "Include Error Detail=True",
+ "Host=example.cloud.com",
+ "Port=2345",
+ "Database=product-database",
+ "Username=products-user",
+ "Password=products-secret"
+ }, options => options.WithoutStrictOrdering());
+
+ ExtractConnectionStringParameters(ordersDbOptions.ConnectionString).Should().BeEquivalentTo(new List
+ {
+ "Log Parameters=True",
+ "Host=example.cloud.com",
+ "Port=2345",
+ "Database=order-database",
+ "Username=orders-user",
+ "Password=orders-secret"
+ }, options => options.WithoutStrictOrdering());
+
+ void MapServiceBindingsForCustomPostgreSqlBroker(string brokerName)
+ {
+ var options = builder.Configuration.GetSection("vcap").Get();
+
+ foreach (CloudFoundryService service in options?.Services.Where(pair => pair.Key == brokerName).SelectMany(pair => pair.Value) ?? [])
+ {
+ builder.Configuration.AddInMemoryCollection(new Dictionary
+ {
+ // Map credentials into the property names expected by NpgsqlConnectionStringBuilder.
+ [$"steeltoe:service-bindings:postgresql:{service.Name}:host"] = service.Credentials["custom-hostname-key"].Value,
+ [$"steeltoe:service-bindings:postgresql:{service.Name}:port"] = service.Credentials["custom-port-key"].Value,
+ [$"steeltoe:service-bindings:postgresql:{service.Name}:username"] = service.Credentials["custom-username-key"].Value,
+ [$"steeltoe:service-bindings:postgresql:{service.Name}:password"] = service.Credentials["custom-password-key"].Value,
+ [$"steeltoe:service-bindings:postgresql:{service.Name}:database"] = service.Credentials["custom-database-name-key"].Value
+ });
+ }
+ }
+ }
+
+ [Fact]
+ public async Task Third_party_service_bindings_can_be_combined_with_builtin()
+ {
+ var appSettings = new Dictionary
+ {
+ ["Steeltoe:Client:PostgreSql:products-db:ConnectionString"] = "Include Error Detail=true;host=localhost",
+ ["Steeltoe:Client:PostgreSql:orders-db:ConnectionString"] = "Log Parameters=true;port=9999",
+ ["Steeltoe:Client:RabbitMQ:transaction-queue:ConnectionString"] = "amqp://localhost?connection_timeout=5000&heartbeat=5&unknown=local"
+ };
+
+ const string vcapServicesJson = """
+ {
+ "postgres": [
+ {
+ "name": "products-db",
+ "credentials": {
+ "custom-hostname-key": "example.cloud.com",
+ "custom-port-key": 2345,
+ "custom-username-key": "products-user",
+ "custom-password-key": "products-secret",
+ "custom-database-name-key": "product-database"
+ }
+ },
+ {
+ "name": "orders-db",
+ "credentials": {
+ "custom-hostname-key": "example.cloud.com",
+ "custom-port-key": 2345,
+ "custom-username-key": "orders-user",
+ "custom-password-key": "orders-secret",
+ "custom-database-name-key": "order-database"
+ }
+ }
+ ],
+ "p.rabbitmq": [
+ {
+ "name": "transaction-queue",
+ "tags": [
+ "rabbitmq"
+ ],
+ "credentials": {
+ "protocols": {
+ "amqp+ssl": {
+ "host": "messaging.cloud.com",
+ "port": 2765,
+ "username": "app-user",
+ "password": "secret",
+ "vhost": "transactions"
+ }
+ },
+ "ssl": true,
+ "unknown": "remote"
+ }
+ }
+ ]
+ }
+ """;
+
+ var reader = new CloudFoundryMemorySettingsReader
+ {
+ ServicesJson = vcapServicesJson
+ };
+
+ WebApplicationBuilder builder = TestWebApplicationBuilderFactory.Create();
+ builder.Configuration.AddInMemoryCollection(appSettings);
+ builder.Configuration.AddCloudFoundry(reader);
+ MapServiceBindingsForCustomPostgreSqlBroker("postgres");
+ builder.AddPostgreSql(options => options.SkipDefaultServiceBindings = true, null);
+ MapExtraRabbitMQServiceBindingsUsingDefaultBroker("p.rabbitmq");
+ builder.AddRabbitMQ(null, null, new StringServiceBindingsReader(vcapServicesJson));
+ await using WebApplication app = builder.Build();
+
+ var postgreSqlOptionsMonitor = app.Services.GetRequiredService>();
+ PostgreSqlOptions productsDbOptions = postgreSqlOptionsMonitor.Get("products-db");
+ PostgreSqlOptions ordersDbOptions = postgreSqlOptionsMonitor.Get("orders-db");
+
+ var rabbitMQOptionsMonitor = app.Services.GetRequiredService>();
+ RabbitMQOptions transactionQueueOptions = rabbitMQOptionsMonitor.Get("transaction-queue");
+
+ ExtractConnectionStringParameters(productsDbOptions.ConnectionString).Should().BeEquivalentTo(new List
+ {
+ "Include Error Detail=True",
+ "Host=example.cloud.com",
+ "Port=2345",
+ "Database=product-database",
+ "Username=products-user",
+ "Password=products-secret"
+ }, options => options.WithoutStrictOrdering());
+
+ ExtractConnectionStringParameters(ordersDbOptions.ConnectionString).Should().BeEquivalentTo(new List
+ {
+ "Log Parameters=True",
+ "Host=example.cloud.com",
+ "Port=2345",
+ "Database=order-database",
+ "Username=orders-user",
+ "Password=orders-secret"
+ }, options => options.WithoutStrictOrdering());
+
+ transactionQueueOptions.ConnectionString.Should().Be(
+ "amqps://app-user:secret@messaging.cloud.com:2765/transactions?connection_timeout=5000&heartbeat=5&unknown=remote");
+
+ void MapServiceBindingsForCustomPostgreSqlBroker(string brokerName)
+ {
+ var options = builder.Configuration.GetSection("vcap").Get();
+
+ foreach (CloudFoundryService service in options?.Services.Where(pair => pair.Key == brokerName).SelectMany(pair => pair.Value) ?? [])
+ {
+ builder.Configuration.AddInMemoryCollection(new Dictionary
+ {
+ // Map third-party credentials into the property names expected by NpgsqlConnectionStringBuilder.
+ [$"steeltoe:service-bindings:postgresql:{service.Name}:host"] = service.Credentials["custom-hostname-key"].Value,
+ [$"steeltoe:service-bindings:postgresql:{service.Name}:port"] = service.Credentials["custom-port-key"].Value,
+ [$"steeltoe:service-bindings:postgresql:{service.Name}:username"] = service.Credentials["custom-username-key"].Value,
+ [$"steeltoe:service-bindings:postgresql:{service.Name}:password"] = service.Credentials["custom-password-key"].Value,
+ [$"steeltoe:service-bindings:postgresql:{service.Name}:database"] = service.Credentials["custom-database-name-key"].Value
+ });
+ }
+ }
+
+ void MapExtraRabbitMQServiceBindingsUsingDefaultBroker(string brokerName)
+ {
+ var options = builder.Configuration.GetSection("vcap").Get();
+
+ foreach (CloudFoundryService service in options?.Services.Where(pair => pair.Key == brokerName).SelectMany(pair => pair.Value) ?? [])
+ {
+ builder.Configuration.AddInMemoryCollection(new Dictionary
+ {
+ // Map third-party 'unknown' credential, in addition to built-in broker parameters.
+ [$"steeltoe:service-bindings:rabbitmq:{service.Name}:unknown"] = service.Credentials["unknown"].Value
+ });
+ }
+ }
+ }
+
+ private static List ExtractConnectionStringParameters(string? connectionString)
+ {
+ List entries = [];
+
+ if (connectionString != null)
+ {
+ foreach (string parameter in connectionString.Split(';'))
+ {
+ string[] nameValuePair = parameter.Split('=', 2);
+
+ if (nameValuePair.Length == 2)
+ {
+ string name = nameValuePair[0];
+ string value = nameValuePair[1];
+
+ entries.Add($"{name}={value}");
+ }
+ }
+ }
+
+ return entries;
+ }
+}
diff --git a/src/Connectors/test/Connectors.Test/MongoDb/MongoDbConnectorTest.cs b/src/Connectors/test/Connectors.Test/MongoDb/MongoDbConnectorTest.cs
index 3d200dcd08..96765a8d07 100644
--- a/src/Connectors/test/Connectors.Test/MongoDb/MongoDbConnectorTest.cs
+++ b/src/Connectors/test/Connectors.Test/MongoDb/MongoDbConnectorTest.cs
@@ -148,9 +148,8 @@ public async Task Binds_options_with_CloudFoundry_service_bindings()
};
WebApplicationBuilder builder = TestWebApplicationBuilderFactory.Create();
- builder.Configuration.AddCloudFoundryServiceBindings(new StringServiceBindingsReader(MultiVcapServicesJson));
builder.Configuration.AddInMemoryCollection(appSettings);
- builder.AddMongoDb();
+ builder.AddMongoDb(null, null, new StringServiceBindingsReader(MultiVcapServicesJson));
await using WebApplication app = builder.Build();
var optionsMonitor = app.Services.GetRequiredService>();
@@ -270,8 +269,7 @@ .. app.Services.GetServices().Should().HaveCount(2).And.AllB
public async Task Registers_default_connection_string_when_only_single_server_binding_found()
{
WebApplicationBuilder builder = TestWebApplicationBuilderFactory.Create();
- builder.Configuration.AddCloudFoundryServiceBindings(new StringServiceBindingsReader(SingleVcapServicesJson));
- builder.AddMongoDb();
+ builder.AddMongoDb(null, null, new StringServiceBindingsReader(SingleVcapServicesJson));
await using WebApplication app = builder.Build();
var connectorFactory = app.Services.GetRequiredService>();
diff --git a/src/Connectors/test/Connectors.Test/MySql/MySqlConnector/MySqlConnectorTest.cs b/src/Connectors/test/Connectors.Test/MySql/MySqlConnector/MySqlConnectorTest.cs
index 4aec658cbf..29a17920e0 100644
--- a/src/Connectors/test/Connectors.Test/MySql/MySqlConnector/MySqlConnectorTest.cs
+++ b/src/Connectors/test/Connectors.Test/MySql/MySqlConnector/MySqlConnectorTest.cs
@@ -115,7 +115,7 @@ public async Task Binds_options_without_service_bindings()
WebApplicationBuilder builder = TestWebApplicationBuilderFactory.Create();
builder.Configuration.AddInMemoryCollection(appSettings);
- builder.AddMySql(MySqlPackageResolver.MySqlConnectorOnly);
+ builder.AddMySql(MySqlPackageResolver.MySqlConnectorOnly, null, null, null);
builder.Services.Configure("myMySqlServiceOne", options => options.ConnectionString += ";Use Compression=false");
await using WebApplication app = builder.Build();
@@ -153,9 +153,8 @@ public async Task Binds_options_with_CloudFoundry_service_bindings()
};
WebApplicationBuilder builder = TestWebApplicationBuilderFactory.Create();
- builder.Configuration.AddCloudFoundryServiceBindings(new StringServiceBindingsReader(MultiVcapServicesJson));
builder.Configuration.AddInMemoryCollection(appSettings);
- builder.AddMySql(MySqlPackageResolver.MySqlConnectorOnly);
+ builder.AddMySql(MySqlPackageResolver.MySqlConnectorOnly, null, null, new StringServiceBindingsReader(MultiVcapServicesJson));
await using WebApplication app = builder.Build();
var optionsMonitor = app.Services.GetRequiredService>();
@@ -235,7 +234,7 @@ public async Task Registers_ConnectorFactory()
WebApplicationBuilder builder = TestWebApplicationBuilderFactory.Create();
builder.Configuration.AddInMemoryCollection(appSettings);
- builder.AddMySql(MySqlPackageResolver.MySqlConnectorOnly);
+ builder.AddMySql(MySqlPackageResolver.MySqlConnectorOnly, null, null, null);
await using WebApplication app = builder.Build();
var connectorFactory = app.Services.GetRequiredService>();
@@ -262,7 +261,7 @@ public async Task Registers_HealthContributors()
WebApplicationBuilder builder = TestWebApplicationBuilderFactory.Create();
builder.Configuration.AddInMemoryCollection(appSettings);
- builder.AddMySql(MySqlPackageResolver.MySqlConnectorOnly);
+ builder.AddMySql(MySqlPackageResolver.MySqlConnectorOnly, null, null, null);
await using WebApplication app = builder.Build();
RelationalDatabaseHealthContributor[] contributors =
@@ -283,8 +282,7 @@ .. app.Services.GetServices().Should().HaveCount(2).And.AllB
public async Task Registers_default_connection_string_when_only_single_server_binding_found()
{
WebApplicationBuilder builder = TestWebApplicationBuilderFactory.Create();
- builder.Configuration.AddCloudFoundryServiceBindings(new StringServiceBindingsReader(SingleVcapServicesJson));
- builder.AddMySql(MySqlPackageResolver.MySqlConnectorOnly);
+ builder.AddMySql(MySqlPackageResolver.MySqlConnectorOnly, null, null, new StringServiceBindingsReader(SingleVcapServicesJson));
await using WebApplication app = builder.Build();
var connectorFactory = app.Services.GetRequiredService>();
@@ -312,7 +310,7 @@ public async Task Registers_default_connection_string_when_only_default_client_b
WebApplicationBuilder builder = TestWebApplicationBuilderFactory.Create();
builder.Configuration.AddInMemoryCollection(appSettings);
- builder.AddMySql(MySqlPackageResolver.MySqlConnectorOnly);
+ builder.AddMySql(MySqlPackageResolver.MySqlConnectorOnly, null, null, null);
await using WebApplication app = builder.Build();
var connectorFactory = app.Services.GetRequiredService>();
diff --git a/src/Connectors/test/Connectors.Test/MySql/Oracle/MySqlConnectorTest.cs b/src/Connectors/test/Connectors.Test/MySql/Oracle/MySqlConnectorTest.cs
index 05f9d0696c..144e1bd47a 100644
--- a/src/Connectors/test/Connectors.Test/MySql/Oracle/MySqlConnectorTest.cs
+++ b/src/Connectors/test/Connectors.Test/MySql/Oracle/MySqlConnectorTest.cs
@@ -115,7 +115,7 @@ public async Task Binds_options_without_service_bindings()
WebApplicationBuilder builder = TestWebApplicationBuilderFactory.Create();
builder.Configuration.AddInMemoryCollection(appSettings);
- builder.AddMySql(MySqlPackageResolver.OracleOnly);
+ builder.AddMySql(MySqlPackageResolver.OracleOnly, null, null, null);
builder.Services.Configure("myMySqlServiceOne", options => options.ConnectionString += ";Use Compression=false");
await using WebApplication app = builder.Build();
@@ -153,9 +153,8 @@ public async Task Binds_options_with_CloudFoundry_service_bindings()
};
WebApplicationBuilder builder = TestWebApplicationBuilderFactory.Create();
- builder.Configuration.AddCloudFoundryServiceBindings(new StringServiceBindingsReader(MultiVcapServicesJson));
builder.Configuration.AddInMemoryCollection(appSettings);
- builder.AddMySql(MySqlPackageResolver.OracleOnly);
+ builder.AddMySql(MySqlPackageResolver.OracleOnly, null, null, new StringServiceBindingsReader(MultiVcapServicesJson));
await using WebApplication app = builder.Build();
var optionsMonitor = app.Services.GetRequiredService>();
@@ -235,7 +234,7 @@ public async Task Registers_ConnectorFactory()
WebApplicationBuilder builder = TestWebApplicationBuilderFactory.Create();
builder.Configuration.AddInMemoryCollection(appSettings);
- builder.AddMySql(MySqlPackageResolver.OracleOnly);
+ builder.AddMySql(MySqlPackageResolver.OracleOnly, null, null, null);
await using WebApplication app = builder.Build();
var connectorFactory = app.Services.GetRequiredService>();
@@ -262,7 +261,7 @@ public async Task Registers_HealthContributors()
WebApplicationBuilder builder = TestWebApplicationBuilderFactory.Create();
builder.Configuration.AddInMemoryCollection(appSettings);
- builder.AddMySql(MySqlPackageResolver.OracleOnly);
+ builder.AddMySql(MySqlPackageResolver.OracleOnly, null, null, null);
await using WebApplication app = builder.Build();
RelationalDatabaseHealthContributor[] contributors =
@@ -283,8 +282,7 @@ .. app.Services.GetServices().Should().HaveCount(2).And.AllB
public async Task Registers_default_connection_string_when_only_single_server_binding_found()
{
WebApplicationBuilder builder = TestWebApplicationBuilderFactory.Create();
- builder.Configuration.AddCloudFoundryServiceBindings(new StringServiceBindingsReader(SingleVcapServicesJson));
- builder.AddMySql(MySqlPackageResolver.OracleOnly);
+ builder.AddMySql(MySqlPackageResolver.OracleOnly, null, null, new StringServiceBindingsReader(SingleVcapServicesJson));
await using WebApplication app = builder.Build();
var connectorFactory = app.Services.GetRequiredService>();
@@ -312,7 +310,7 @@ public async Task Registers_default_connection_string_when_only_default_client_b
WebApplicationBuilder builder = TestWebApplicationBuilderFactory.Create();
builder.Configuration.AddInMemoryCollection(appSettings);
- builder.AddMySql(MySqlPackageResolver.OracleOnly);
+ builder.AddMySql(MySqlPackageResolver.OracleOnly, null, null, null);
await using WebApplication app = builder.Build();
var connectorFactory = app.Services.GetRequiredService>();
diff --git a/src/Connectors/test/Connectors.Test/PostgreSql/PostgreSqlConnectorTest.cs b/src/Connectors/test/Connectors.Test/PostgreSql/PostgreSqlConnectorTest.cs
index 9db3f840b4..8ab17a04ee 100644
--- a/src/Connectors/test/Connectors.Test/PostgreSql/PostgreSqlConnectorTest.cs
+++ b/src/Connectors/test/Connectors.Test/PostgreSql/PostgreSqlConnectorTest.cs
@@ -9,7 +9,6 @@
using Npgsql;
using Steeltoe.Common.HealthChecks;
using Steeltoe.Common.TestResources;
-using Steeltoe.Configuration.CloudFoundry;
using Steeltoe.Configuration.CloudFoundry.ServiceBindings;
using Steeltoe.Configuration.Kubernetes.ServiceBindings;
using Steeltoe.Connectors.PostgreSql;
@@ -233,9 +232,8 @@ public async Task Binds_options_with_CloudFoundry_service_bindings()
};
WebApplicationBuilder builder = TestWebApplicationBuilderFactory.Create();
- builder.Configuration.AddCloudFoundryServiceBindings(new StringServiceBindingsReader(MultiVcapServicesJson));
builder.Configuration.AddInMemoryCollection(appSettings);
- builder.AddPostgreSql();
+ builder.AddPostgreSql(null, null, new StringServiceBindingsReader(MultiVcapServicesJson));
await using WebApplication app = builder.Build();
var optionsMonitor = app.Services.GetRequiredService>();
@@ -395,97 +393,6 @@ public async Task Binds_options_with_Kubernetes_service_bindings()
}, options => options.WithoutStrictOrdering());
}
- [Fact]
- public async Task Binds_options_with_third_party_service_bindings()
- {
- var appSettings = new Dictionary
- {
- ["Steeltoe:Client:PostgreSql:products-db:ConnectionString"] = "Include Error Detail=true;host=localhost",
- ["Steeltoe:Client:PostgreSql:orders-db:ConnectionString"] = "Log Parameters=true;port=9999"
- };
-
- var reader = new CloudFoundryMemorySettingsReader
- {
- ServicesJson = """
- {
- "custom-postgres-broker": [
- {
- "name": "products-db",
- "credentials": {
- "custom-hostname-key": "example.cloud.com",
- "custom-port-key": 2345,
- "custom-username-key": "products-user",
- "custom-password-key": "products-secret",
- "custom-database-name-key": "product-database"
- }
- },
- {
- "name": "orders-db",
- "credentials": {
- "custom-hostname-key": "example.cloud.com",
- "custom-port-key": 2345,
- "custom-username-key": "orders-user",
- "custom-password-key": "orders-secret",
- "custom-database-name-key": "order-database"
- }
- },
- ]
- }
- """
- };
-
- WebApplicationBuilder builder = TestWebApplicationBuilderFactory.Create();
- builder.Configuration.AddInMemoryCollection(appSettings);
- builder.Configuration.AddCloudFoundry(reader);
- MapCustomServiceBindings("custom-postgres-broker");
- builder.AddPostgreSql(options => options.SkipDefaultServiceBindings = true, null);
- await using WebApplication app = builder.Build();
-
- var optionsMonitor = app.Services.GetRequiredService>();
-
- PostgreSqlOptions productsDbOptions = optionsMonitor.Get("products-db");
-
- ExtractConnectionStringParameters(productsDbOptions.ConnectionString).Should().BeEquivalentTo(new List
- {
- "Include Error Detail=True",
- "Host=example.cloud.com",
- "Port=2345",
- "Database=product-database",
- "Username=products-user",
- "Password=products-secret"
- }, options => options.WithoutStrictOrdering());
-
- PostgreSqlOptions ordersDbOptions = optionsMonitor.Get("orders-db");
-
- ExtractConnectionStringParameters(ordersDbOptions.ConnectionString).Should().BeEquivalentTo(new List
- {
- "Log Parameters=True",
- "Host=example.cloud.com",
- "Port=2345",
- "Database=order-database",
- "Username=orders-user",
- "Password=orders-secret"
- }, options => options.WithoutStrictOrdering());
-
- void MapCustomServiceBindings(string brokerName)
- {
- var options = builder.Configuration.GetSection("vcap").Get();
-
- foreach (CloudFoundryService service in options?.Services.Where(pair => pair.Key == brokerName).SelectMany(pair => pair.Value) ?? [])
- {
- builder.Configuration.AddInMemoryCollection(new Dictionary
- {
- // Map credentials into the property names expected by NpgsqlConnectionStringBuilder.
- [$"steeltoe:service-bindings:postgresql:{service.Name}:host"] = service.Credentials["custom-hostname-key"].Value,
- [$"steeltoe:service-bindings:postgresql:{service.Name}:port"] = service.Credentials["custom-port-key"].Value,
- [$"steeltoe:service-bindings:postgresql:{service.Name}:username"] = service.Credentials["custom-username-key"].Value,
- [$"steeltoe:service-bindings:postgresql:{service.Name}:password"] = service.Credentials["custom-password-key"].Value,
- [$"steeltoe:service-bindings:postgresql:{service.Name}:database"] = service.Credentials["custom-database-name-key"].Value
- });
- }
- }
- }
-
[Fact]
public async Task Registers_ConnectorFactory()
{
@@ -553,7 +460,7 @@ public async Task Skips_HealthContributors_when_AspNetCore_health_checks_are_reg
WebApplicationBuilder builder = TestWebApplicationBuilderFactory.Create();
builder.Configuration.AddInMemoryCollection(appSettings);
builder.Services.AddHealthChecks();
- builder.AddPostgreSql(null, null);
+ builder.AddPostgreSql();
await using WebApplication app = builder.Build();
app.Services.GetServices().Should().BeEmpty();
@@ -585,9 +492,8 @@ public async Task Registers_default_connection_string_when_single_server_binding
};
WebApplicationBuilder builder = TestWebApplicationBuilderFactory.Create();
- builder.Configuration.AddCloudFoundryServiceBindings(new StringServiceBindingsReader(SingleVcapServicesJson));
builder.Configuration.AddInMemoryCollection(appSettings);
- builder.AddPostgreSql();
+ builder.AddPostgreSql(null, null, new StringServiceBindingsReader(SingleVcapServicesJson));
await using WebApplication app = builder.Build();
var connectorFactory = app.Services.GetRequiredService>();
@@ -618,8 +524,7 @@ public async Task Registers_default_connection_string_when_single_server_binding
public async Task Registers_default_connection_string_when_only_single_server_binding_found()
{
WebApplicationBuilder builder = TestWebApplicationBuilderFactory.Create();
- builder.Configuration.AddCloudFoundryServiceBindings(new StringServiceBindingsReader(SingleVcapServicesJson));
- builder.AddPostgreSql();
+ builder.AddPostgreSql(null, null, new StringServiceBindingsReader(SingleVcapServicesJson));
await using WebApplication app = builder.Build();
var connectorFactory = app.Services.GetRequiredService>();
@@ -716,9 +621,8 @@ public async Task Registers_no_default_connection_string_when_multiple_server_bi
};
WebApplicationBuilder builder = TestWebApplicationBuilderFactory.Create();
- builder.Configuration.AddCloudFoundryServiceBindings(new StringServiceBindingsReader(MultiVcapServicesJson));
builder.Configuration.AddInMemoryCollection(appSettings);
- builder.AddPostgreSql();
+ builder.AddPostgreSql(null, null, new StringServiceBindingsReader(MultiVcapServicesJson));
await using WebApplication app = builder.Build();
var connectorFactory = app.Services.GetRequiredService>();
@@ -744,9 +648,8 @@ public async Task Registers_no_default_connection_string_when_single_server_bind
};
WebApplicationBuilder builder = TestWebApplicationBuilderFactory.Create();
- builder.Configuration.AddCloudFoundryServiceBindings(new StringServiceBindingsReader(SingleVcapServicesJson));
builder.Configuration.AddInMemoryCollection(appSettings);
- builder.AddPostgreSql();
+ builder.AddPostgreSql(null, null, new StringServiceBindingsReader(SingleVcapServicesJson));
await using WebApplication app = builder.Build();
var connectorFactory = app.Services.GetRequiredService>();
@@ -769,9 +672,8 @@ public async Task Registers_no_default_connection_string_when_service_and_client
};
WebApplicationBuilder builder = TestWebApplicationBuilderFactory.Create();
- builder.Configuration.AddCloudFoundryServiceBindings(new StringServiceBindingsReader(SingleVcapServicesJson));
builder.Configuration.AddInMemoryCollection(appSettings);
- builder.AddPostgreSql();
+ builder.AddPostgreSql(null, null, new StringServiceBindingsReader(SingleVcapServicesJson));
await using WebApplication app = builder.Build();
var connectorFactory = app.Services.GetRequiredService>();
diff --git a/src/Connectors/test/Connectors.Test/RabbitMQ/RabbitMQConnectorTest.cs b/src/Connectors/test/Connectors.Test/RabbitMQ/RabbitMQConnectorTest.cs
index 5ec987837a..6c944dc0b1 100644
--- a/src/Connectors/test/Connectors.Test/RabbitMQ/RabbitMQConnectorTest.cs
+++ b/src/Connectors/test/Connectors.Test/RabbitMQ/RabbitMQConnectorTest.cs
@@ -218,9 +218,8 @@ public async Task Binds_options_with_CloudFoundry_service_bindings()
};
WebApplicationBuilder builder = TestWebApplicationBuilderFactory.Create();
- builder.Configuration.AddCloudFoundryServiceBindings(new StringServiceBindingsReader(MultiVcapServicesJson));
builder.Configuration.AddInMemoryCollection(appSettings);
- builder.AddRabbitMQ();
+ builder.AddRabbitMQ(null, null, new StringServiceBindingsReader(MultiVcapServicesJson));
await using WebApplication app = builder.Build();
var optionsMonitor = app.Services.GetRequiredService>();
@@ -371,7 +370,6 @@ public async Task Can_connect_to_running_server()
public async Task Registers_default_connection_string_when_only_single_server_binding_found()
{
WebApplicationBuilder builder = TestWebApplicationBuilderFactory.Create();
- builder.Configuration.AddCloudFoundryServiceBindings(new StringServiceBindingsReader(SingleVcapServicesJson));
builder.AddRabbitMQ(null, addOptions =>
{
@@ -382,7 +380,7 @@ public async Task Registers_default_connection_string_when_only_single_server_bi
return new FakeConnection(options.ConnectionString);
};
- });
+ }, new StringServiceBindingsReader(SingleVcapServicesJson));
await using WebApplication app = builder.Build();
diff --git a/src/Connectors/test/Connectors.Test/Redis/RedisConnectorTest.cs b/src/Connectors/test/Connectors.Test/Redis/RedisConnectorTest.cs
index afd08db3f1..5d5e23f609 100644
--- a/src/Connectors/test/Connectors.Test/Redis/RedisConnectorTest.cs
+++ b/src/Connectors/test/Connectors.Test/Redis/RedisConnectorTest.cs
@@ -131,9 +131,8 @@ public async Task Binds_options_with_CloudFoundry_service_bindings()
};
WebApplicationBuilder builder = TestWebApplicationBuilderFactory.Create();
- builder.Configuration.AddCloudFoundryServiceBindings(new StringServiceBindingsReader(MultiVcapServicesJson));
builder.Configuration.AddInMemoryCollection(appSettings);
- builder.AddRedis();
+ builder.AddRedis(null, null, new StringServiceBindingsReader(MultiVcapServicesJson));
await using WebApplication app = builder.Build();
var optionsMonitor = app.Services.GetRequiredService>();
@@ -308,7 +307,6 @@ .. app.Services.GetServices().Should().HaveCount(2).And.AllB
public async Task Registers_default_connection_string_when_only_single_server_binding_found()
{
WebApplicationBuilder builder = TestWebApplicationBuilderFactory.Create();
- builder.Configuration.AddCloudFoundryServiceBindings(new StringServiceBindingsReader(SingleVcapServicesJson));
builder.AddRedis(null, addOptions =>
{
@@ -319,7 +317,7 @@ public async Task Registers_default_connection_string_when_only_single_server_bi
return GetMockedConnectionMultiplexer(options.ConnectionString);
};
- });
+ }, new StringServiceBindingsReader(SingleVcapServicesJson));
await using WebApplication app = builder.Build();
diff --git a/src/Connectors/test/Connectors.Test/SqlServer/MicrosoftData/SqlServerConnectorTest.cs b/src/Connectors/test/Connectors.Test/SqlServer/MicrosoftData/SqlServerConnectorTest.cs
index 506646654f..35ed4b9ad2 100644
--- a/src/Connectors/test/Connectors.Test/SqlServer/MicrosoftData/SqlServerConnectorTest.cs
+++ b/src/Connectors/test/Connectors.Test/SqlServer/MicrosoftData/SqlServerConnectorTest.cs
@@ -147,7 +147,7 @@ public async Task Binds_options_without_service_bindings()
WebApplicationBuilder builder = TestWebApplicationBuilderFactory.Create();
builder.Configuration.AddInMemoryCollection(appSettings);
- builder.AddSqlServer(SqlServerPackageResolver.MicrosoftDataOnly);
+ builder.AddSqlServer(SqlServerPackageResolver.MicrosoftDataOnly, null, null, null);
builder.Services.Configure("mySqlServerServiceOne", options => options.ConnectionString += ";Encrypt=false");
await using WebApplication app = builder.Build();
@@ -185,9 +185,8 @@ public async Task Binds_options_with_CloudFoundry_service_bindings()
};
WebApplicationBuilder builder = TestWebApplicationBuilderFactory.Create();
- builder.Configuration.AddCloudFoundryServiceBindings(new StringServiceBindingsReader(MultiVcapServicesJson));
builder.Configuration.AddInMemoryCollection(appSettings);
- builder.AddSqlServer(SqlServerPackageResolver.MicrosoftDataOnly);
+ builder.AddSqlServer(SqlServerPackageResolver.MicrosoftDataOnly, null, null, new StringServiceBindingsReader(MultiVcapServicesJson));
await using WebApplication app = builder.Build();
var optionsMonitor = app.Services.GetRequiredService>();
@@ -225,7 +224,7 @@ public async Task Registers_ConnectorFactory()
WebApplicationBuilder builder = TestWebApplicationBuilderFactory.Create();
builder.Configuration.AddInMemoryCollection(appSettings);
- builder.AddSqlServer(SqlServerPackageResolver.MicrosoftDataOnly);
+ builder.AddSqlServer(SqlServerPackageResolver.MicrosoftDataOnly, null, null, null);
await using WebApplication app = builder.Build();
var connectorFactory = app.Services.GetRequiredService>();
@@ -252,7 +251,7 @@ public async Task Registers_HealthContributors()
WebApplicationBuilder builder = TestWebApplicationBuilderFactory.Create();
builder.Configuration.AddInMemoryCollection(appSettings);
- builder.AddSqlServer(SqlServerPackageResolver.MicrosoftDataOnly);
+ builder.AddSqlServer(SqlServerPackageResolver.MicrosoftDataOnly, null, null, null);
await using WebApplication app = builder.Build();
RelationalDatabaseHealthContributor[] contributors =
@@ -273,8 +272,7 @@ .. app.Services.GetServices().Should().HaveCount(2).And.AllB
public async Task Registers_default_connection_string_when_only_single_server_binding_found()
{
WebApplicationBuilder builder = TestWebApplicationBuilderFactory.Create();
- builder.Configuration.AddCloudFoundryServiceBindings(new StringServiceBindingsReader(SingleVcapServicesJson));
- builder.AddSqlServer(SqlServerPackageResolver.MicrosoftDataOnly);
+ builder.AddSqlServer(SqlServerPackageResolver.MicrosoftDataOnly, null, null, new StringServiceBindingsReader(SingleVcapServicesJson));
await using WebApplication app = builder.Build();
var connectorFactory = app.Services.GetRequiredService>();
@@ -302,7 +300,7 @@ public async Task Registers_default_connection_string_when_only_default_client_b
WebApplicationBuilder builder = TestWebApplicationBuilderFactory.Create();
builder.Configuration.AddInMemoryCollection(appSettings);
- builder.AddSqlServer(SqlServerPackageResolver.MicrosoftDataOnly);
+ builder.AddSqlServer(SqlServerPackageResolver.MicrosoftDataOnly, null, null, null);
await using WebApplication app = builder.Build();
var connectorFactory = app.Services.GetRequiredService>();
diff --git a/src/Connectors/test/Connectors.Test/SqlServer/SystemData/SqlServerConnectorTest.cs b/src/Connectors/test/Connectors.Test/SqlServer/SystemData/SqlServerConnectorTest.cs
index 42972a6339..3dd16da833 100644
--- a/src/Connectors/test/Connectors.Test/SqlServer/SystemData/SqlServerConnectorTest.cs
+++ b/src/Connectors/test/Connectors.Test/SqlServer/SystemData/SqlServerConnectorTest.cs
@@ -149,7 +149,7 @@ public async Task Binds_options_without_service_bindings()
WebApplicationBuilder builder = TestWebApplicationBuilderFactory.Create();
builder.Configuration.AddInMemoryCollection(appSettings);
- builder.AddSqlServer(SqlServerPackageResolver.SystemDataOnly);
+ builder.AddSqlServer(SqlServerPackageResolver.SystemDataOnly, null, null, null);
builder.Services.Configure("mySqlServerServiceOne", options => options.ConnectionString += ";Encrypt=false");
await using WebApplication app = builder.Build();
@@ -187,9 +187,8 @@ public async Task Binds_options_with_CloudFoundry_service_bindings()
};
WebApplicationBuilder builder = TestWebApplicationBuilderFactory.Create();
- builder.Configuration.AddCloudFoundryServiceBindings(new StringServiceBindingsReader(MultiVcapServicesJson));
builder.Configuration.AddInMemoryCollection(appSettings);
- builder.AddSqlServer(SqlServerPackageResolver.SystemDataOnly);
+ builder.AddSqlServer(SqlServerPackageResolver.SystemDataOnly, null, null, new StringServiceBindingsReader(MultiVcapServicesJson));
await using WebApplication app = builder.Build();
var optionsMonitor = app.Services.GetRequiredService>();
@@ -227,7 +226,7 @@ public async Task Registers_ConnectorFactory()
WebApplicationBuilder builder = TestWebApplicationBuilderFactory.Create();
builder.Configuration.AddInMemoryCollection(appSettings);
- builder.AddSqlServer(SqlServerPackageResolver.SystemDataOnly);
+ builder.AddSqlServer(SqlServerPackageResolver.SystemDataOnly, null, null, null);
await using WebApplication app = builder.Build();
var connectorFactory = app.Services.GetRequiredService>();
@@ -254,7 +253,7 @@ public async Task Registers_HealthContributors()
WebApplicationBuilder builder = TestWebApplicationBuilderFactory.Create();
builder.Configuration.AddInMemoryCollection(appSettings);
- builder.AddSqlServer(SqlServerPackageResolver.SystemDataOnly);
+ builder.AddSqlServer(SqlServerPackageResolver.SystemDataOnly, null, null, null);
await using WebApplication app = builder.Build();
RelationalDatabaseHealthContributor[] contributors =
@@ -275,8 +274,7 @@ .. app.Services.GetServices().Should().HaveCount(2).And.AllB
public async Task Registers_default_connection_string_when_only_single_server_binding_found()
{
WebApplicationBuilder builder = TestWebApplicationBuilderFactory.Create();
- builder.Configuration.AddCloudFoundryServiceBindings(new StringServiceBindingsReader(SingleVcapServicesJson));
- builder.AddSqlServer(SqlServerPackageResolver.SystemDataOnly);
+ builder.AddSqlServer(SqlServerPackageResolver.SystemDataOnly, null, null, new StringServiceBindingsReader(SingleVcapServicesJson));
await using WebApplication app = builder.Build();
var connectorFactory = app.Services.GetRequiredService>();
@@ -304,7 +302,7 @@ public async Task Registers_default_connection_string_when_only_default_client_b
WebApplicationBuilder builder = TestWebApplicationBuilderFactory.Create();
builder.Configuration.AddInMemoryCollection(appSettings);
- builder.AddSqlServer(SqlServerPackageResolver.SystemDataOnly);
+ builder.AddSqlServer(SqlServerPackageResolver.SystemDataOnly, null, null, null);
await using WebApplication app = builder.Build();
var connectorFactory = app.Services.GetRequiredService>();
diff --git a/src/Connectors/test/EntityFrameworkCore.Test/MySql/Oracle/MySqlDbContextOptionsBuilderExtensionsTest.cs b/src/Connectors/test/EntityFrameworkCore.Test/MySql/Oracle/MySqlDbContextOptionsBuilderExtensionsTest.cs
index bbab683b37..735addf178 100644
--- a/src/Connectors/test/EntityFrameworkCore.Test/MySql/Oracle/MySqlDbContextOptionsBuilderExtensionsTest.cs
+++ b/src/Connectors/test/EntityFrameworkCore.Test/MySql/Oracle/MySqlDbContextOptionsBuilderExtensionsTest.cs
@@ -26,7 +26,7 @@ public async Task Registers_connection_string_for_default_service_binding()
WebApplicationBuilder builder = TestWebApplicationBuilderFactory.Create();
builder.Configuration.AddInMemoryCollection(appSettings);
- builder.AddMySql(MySqlPackageResolver.OracleOnly);
+ builder.AddMySql(MySqlPackageResolver.OracleOnly, null, null, null);
builder.Services.Configure(options => options.ConnectionString += ";Use Compression=false");
builder.Services.AddDbContext((serviceProvider, options) => SteeltoeExtensions.UseMySql(options, serviceProvider,
@@ -51,7 +51,7 @@ public async Task Registers_connection_string_for_named_service_binding()
WebApplicationBuilder builder = TestWebApplicationBuilderFactory.Create();
builder.Configuration.AddInMemoryCollection(appSettings);
- builder.AddMySql(MySqlPackageResolver.OracleOnly);
+ builder.AddMySql(MySqlPackageResolver.OracleOnly, null, null, null);
builder.Services.Configure("myMySqlService", options => options.ConnectionString += ";Use Compression=false");
builder.Services.AddDbContext((serviceProvider, options) => SteeltoeExtensions.UseMySql(options, serviceProvider,
diff --git a/src/Connectors/test/EntityFrameworkCore.Test/MySql/Pomelo/MySqlDbContextOptionsBuilderExtensionsTest.cs b/src/Connectors/test/EntityFrameworkCore.Test/MySql/Pomelo/MySqlDbContextOptionsBuilderExtensionsTest.cs
index 17a40ea71e..7e8e974935 100644
--- a/src/Connectors/test/EntityFrameworkCore.Test/MySql/Pomelo/MySqlDbContextOptionsBuilderExtensionsTest.cs
+++ b/src/Connectors/test/EntityFrameworkCore.Test/MySql/Pomelo/MySqlDbContextOptionsBuilderExtensionsTest.cs
@@ -30,7 +30,7 @@ public async Task Registers_connection_string_for_default_service_binding()
WebApplicationBuilder builder = TestWebApplicationBuilderFactory.Create();
builder.Configuration.AddInMemoryCollection(appSettings);
- builder.AddMySql(MySqlPackageResolver.MySqlConnectorOnly);
+ builder.AddMySql(MySqlPackageResolver.MySqlConnectorOnly, null, null, null);
builder.Services.Configure(options => options.ConnectionString += ";Use Compression=false");
builder.Services.AddDbContext((serviceProvider, options) => SteeltoeExtensions.UseMySql(options, serviceProvider,
@@ -60,7 +60,7 @@ public async Task Registers_connection_string_for_named_service_binding()
WebApplicationBuilder builder = TestWebApplicationBuilderFactory.Create();
builder.Configuration.AddInMemoryCollection(appSettings);
- builder.AddMySql(MySqlPackageResolver.MySqlConnectorOnly);
+ builder.AddMySql(MySqlPackageResolver.MySqlConnectorOnly, null, null, null);
builder.Services.Configure("myMySqlService", options => options.ConnectionString += ";Use Compression=false");
builder.Services.AddDbContext((serviceProvider, options) => SteeltoeExtensions.UseMySql(options, serviceProvider,
@@ -80,7 +80,7 @@ public async Task Registers_connection_string_for_named_service_binding()
public async Task Throws_for_missing_connection_string_with_version_detection()
{
WebApplicationBuilder builder = TestWebApplicationBuilderFactory.Create();
- builder.AddMySql(MySqlPackageResolver.MySqlConnectorOnly);
+ builder.AddMySql(MySqlPackageResolver.MySqlConnectorOnly, null, null, null);
builder.Services.AddDbContext((serviceProvider, options) => SteeltoeExtensions.UseMySql(options, serviceProvider,
MySqlEntityFrameworkCorePackageResolver.PomeloOnly));
diff --git a/src/Connectors/test/EntityFrameworkCore.Test/SqlServer/SqlServerDbContextOptionsBuilderExtensionsTest.cs b/src/Connectors/test/EntityFrameworkCore.Test/SqlServer/SqlServerDbContextOptionsBuilderExtensionsTest.cs
index fe02b0faaa..ab6df7b404 100644
--- a/src/Connectors/test/EntityFrameworkCore.Test/SqlServer/SqlServerDbContextOptionsBuilderExtensionsTest.cs
+++ b/src/Connectors/test/EntityFrameworkCore.Test/SqlServer/SqlServerDbContextOptionsBuilderExtensionsTest.cs
@@ -25,7 +25,7 @@ public async Task Registers_connection_string_for_default_service_binding()
WebApplicationBuilder builder = TestWebApplicationBuilderFactory.Create();
builder.Configuration.AddInMemoryCollection(appSettings);
- builder.AddSqlServer(SqlServerPackageResolver.MicrosoftDataOnly);
+ builder.AddSqlServer(SqlServerPackageResolver.MicrosoftDataOnly, null, null, null);
builder.Services.Configure(options => options.ConnectionString += ";Encrypt=false");
builder.Services.AddDbContext((serviceProvider, options) => options.UseSqlServer(serviceProvider));
await using WebApplication app = builder.Build();
@@ -47,7 +47,7 @@ public async Task Registers_connection_string_for_named_service_binding()
WebApplicationBuilder builder = TestWebApplicationBuilderFactory.Create();
builder.Configuration.AddInMemoryCollection(appSettings);
- builder.AddSqlServer(SqlServerPackageResolver.MicrosoftDataOnly);
+ builder.AddSqlServer(SqlServerPackageResolver.MicrosoftDataOnly, null, null, null);
builder.Services.Configure("mySqlServerService", options => options.ConnectionString += ";Encrypt=false");
builder.Services.AddDbContext((serviceProvider, options) => options.UseSqlServer(serviceProvider, "mySqlServerService"));
await using WebApplication app = builder.Build();
diff --git a/src/Discovery/test/Eureka.Test/CloudFoundryTest.cs b/src/Discovery/test/Eureka.Test/CloudFoundryTest.cs
index 9a86f5a7a4..d0b5129b8b 100644
--- a/src/Discovery/test/Eureka.Test/CloudFoundryTest.cs
+++ b/src/Discovery/test/Eureka.Test/CloudFoundryTest.cs
@@ -75,7 +75,7 @@ public async Task NoVCAPEnvVariables_ConfiguresEurekaDiscovery_Correctly()
WebApplicationBuilder builder = TestWebApplicationBuilderFactory.Create();
builder.Configuration.AddJsonStream(stream);
builder.AddCloudFoundryConfiguration();
- builder.Configuration.AddCloudFoundryServiceBindings();
+ builder.Configuration.AddCloudFoundryServiceBindings(CloudFoundryServiceBrokerTypes.Eureka);
builder.Services.AddEurekaDiscoveryClient();
await using WebApplication app = builder.Build();
@@ -269,7 +269,7 @@ public async Task WithVCAPEnvVariables_HostName_ConfiguresEurekaDiscovery_Correc
WebApplicationBuilder builder = TestWebApplicationBuilderFactory.Create();
builder.Configuration.AddJsonStream(stream);
builder.AddCloudFoundryConfiguration();
- builder.Configuration.AddCloudFoundryServiceBindings();
+ builder.Configuration.AddCloudFoundryServiceBindings(CloudFoundryServiceBrokerTypes.Eureka);
builder.Services.AddEurekaDiscoveryClient();
await using WebApplication app = builder.Build();
@@ -464,7 +464,7 @@ public async Task WithVCAPEnvVariables_Route_ConfiguresEurekaDiscovery_Correctly
WebApplicationBuilder builder = TestWebApplicationBuilderFactory.Create();
builder.Configuration.AddJsonStream(stream);
builder.AddCloudFoundryConfiguration();
- builder.Configuration.AddCloudFoundryServiceBindings();
+ builder.Configuration.AddCloudFoundryServiceBindings(CloudFoundryServiceBrokerTypes.Eureka);
builder.Services.AddEurekaDiscoveryClient();
await using WebApplication app = builder.Build();
@@ -661,7 +661,7 @@ public async Task WithVCAPEnvVariables_AppName_Overrides_VCAPBinding()
WebApplicationBuilder builder = TestWebApplicationBuilderFactory.Create();
builder.Configuration.AddJsonStream(stream);
builder.AddCloudFoundryConfiguration();
- builder.Configuration.AddCloudFoundryServiceBindings();
+ builder.Configuration.AddCloudFoundryServiceBindings(CloudFoundryServiceBrokerTypes.Eureka);
builder.Services.AddEurekaDiscoveryClient();
await using WebApplication app = builder.Build();
@@ -760,7 +760,7 @@ public async Task WithVCAPEnvVariables_ButNoUri_DoesNotThrow()
WebApplicationBuilder builder = TestWebApplicationBuilderFactory.Create();
builder.AddCloudFoundryConfiguration();
- builder.Configuration.AddCloudFoundryServiceBindings();
+ builder.Configuration.AddCloudFoundryServiceBindings(CloudFoundryServiceBrokerTypes.Eureka);
builder.Services.AddEurekaDiscoveryClient();
await using WebApplication app = builder.Build();
diff --git a/src/Discovery/test/HttpClients.Test/RegisterMultipleDiscoveryClientsTest.cs b/src/Discovery/test/HttpClients.Test/RegisterMultipleDiscoveryClientsTest.cs
index a4a3a846f1..fe62959c7c 100644
--- a/src/Discovery/test/HttpClients.Test/RegisterMultipleDiscoveryClientsTest.cs
+++ b/src/Discovery/test/HttpClients.Test/RegisterMultipleDiscoveryClientsTest.cs
@@ -231,7 +231,7 @@ public async Task SingleEurekaVCAP_AddsEurekaDiscoveryClient()
var builder = new ConfigurationBuilder();
builder.AddInMemoryCollection(appSettings);
builder.AddCloudFoundry();
- builder.AddCloudFoundryServiceBindings();
+ builder.AddCloudFoundryServiceBindings(CloudFoundryServiceBrokerTypes.Eureka);
IConfiguration configuration = builder.Build();
IServiceCollection services = new ServiceCollection();
@@ -328,7 +328,7 @@ public async Task MultipleEurekaVCAPs_AddsEurekaDiscoveryClientForFirstEntry()
var builder = new ConfigurationBuilder();
builder.AddInMemoryCollection(appSettings);
builder.AddCloudFoundry();
- builder.AddCloudFoundryServiceBindings();
+ builder.AddCloudFoundryServiceBindings(CloudFoundryServiceBrokerTypes.Eureka);
IConfiguration configuration = builder.Build();
IServiceCollection services = new ServiceCollection();
@@ -424,7 +424,10 @@ public void MultipleEurekaVCAPs_LogsWarning()
using var loggerFactory = new LoggerFactory([capturingLoggerProvider]);
var configurationBuilder = new ConfigurationBuilder();
- configurationBuilder.AddCloudFoundryServiceBindings(_ => false, new EnvironmentServiceBindingsReader(), loggerFactory);
+
+ configurationBuilder.AddCloudFoundryServiceBindings(_ => false, new EnvironmentServiceBindingsReader(), CloudFoundryServiceBrokerTypes.Eureka,
+ loggerFactory);
+
_ = configurationBuilder.Build();
IList logMessages = capturingLoggerProvider.GetAll();
@@ -536,7 +539,7 @@ public async Task EurekaWithAccessTokenUri_SendsAuthTokenRequestFirst()
WebApplicationBuilder builder = TestWebApplicationBuilderFactory.Create();
builder.Configuration.AddCloudFoundry();
- builder.Configuration.AddCloudFoundryServiceBindings();
+ builder.Configuration.AddCloudFoundryServiceBindings(CloudFoundryServiceBrokerTypes.Eureka);
builder.Configuration.AddInMemoryCollection(appSettings);
builder.Services.AddEurekaDiscoveryClient();
diff --git a/src/Security/test/Authentication.JwtBearer.Test/PostConfigureJwtBearerOptionsTest.cs b/src/Security/test/Authentication.JwtBearer.Test/PostConfigureJwtBearerOptionsTest.cs
index dd118fa349..290a8e55c0 100644
--- a/src/Security/test/Authentication.JwtBearer.Test/PostConfigureJwtBearerOptionsTest.cs
+++ b/src/Security/test/Authentication.JwtBearer.Test/PostConfigureJwtBearerOptionsTest.cs
@@ -63,7 +63,7 @@ public async Task PostConfigure_ConfiguresForCloudFoundry()
""";
using var servicesScope = new EnvironmentVariableScope("VCAP_SERVICES", vcapServices);
- IConfiguration configuration = new ConfigurationBuilder().AddCloudFoundryServiceBindings().Build();
+ IConfiguration configuration = new ConfigurationBuilder().AddCloudFoundryServiceBindings(CloudFoundryServiceBrokerTypes.Identity).Build();
var services = new ServiceCollection();
services.AddSingleton(configuration);
services.AddAuthentication().AddJwtBearer().ConfigureJwtBearerForCloudFoundry();
@@ -111,7 +111,7 @@ public async Task PostConfigure_ConfiguresForCloudFoundry_AllowMultipleIssuers()
using var applicationScope = new EnvironmentVariableScope("VCAP_APPLICATION", "{}");
using var servicesScope = new EnvironmentVariableScope("VCAP_SERVICES", vcapServices);
- IConfiguration configuration = new ConfigurationBuilder().AddCloudFoundryServiceBindings().Build();
+ IConfiguration configuration = new ConfigurationBuilder().AddCloudFoundryServiceBindings(CloudFoundryServiceBrokerTypes.Identity).Build();
var services = new ServiceCollection();
services.AddSingleton(configuration);
services.AddAuthentication().AddJwtBearer().ConfigureJwtBearerForCloudFoundry();
diff --git a/src/Security/test/Authentication.OpenIdConnect.Test/PostConfigureOpenIdConnectOptionsTest.cs b/src/Security/test/Authentication.OpenIdConnect.Test/PostConfigureOpenIdConnectOptionsTest.cs
index f478b0ebb5..794ad38518 100644
--- a/src/Security/test/Authentication.OpenIdConnect.Test/PostConfigureOpenIdConnectOptionsTest.cs
+++ b/src/Security/test/Authentication.OpenIdConnect.Test/PostConfigureOpenIdConnectOptionsTest.cs
@@ -67,7 +67,7 @@ public async Task PostConfigure_ConfiguresForCloudFoundry()
""";
using var servicesScope = new EnvironmentVariableScope("VCAP_SERVICES", vcapServices);
- IConfiguration configuration = new ConfigurationBuilder().AddCloudFoundryServiceBindings().Build();
+ IConfiguration configuration = new ConfigurationBuilder().AddCloudFoundryServiceBindings(CloudFoundryServiceBrokerTypes.Identity).Build();
var services = new ServiceCollection();
services.AddSingleton(configuration);
From 2d615c97868eab671747b032d628e80784238dbf Mon Sep 17 00:00:00 2001
From: Bart Koelman <104792814+bart-vmware@users.noreply.github.com>
Date: Thu, 23 Apr 2026 13:55:03 +0200
Subject: [PATCH 6/7] Fix broken build
---
.../CloudFoundryServiceBrokerTypes.cs | 37 +++++++++++++++++++
1 file changed, 37 insertions(+)
diff --git a/src/Configuration/src/CloudFoundry/ServiceBindings/CloudFoundryServiceBrokerTypes.cs b/src/Configuration/src/CloudFoundry/ServiceBindings/CloudFoundryServiceBrokerTypes.cs
index 3d0dbf764d..187b30de3b 100644
--- a/src/Configuration/src/CloudFoundry/ServiceBindings/CloudFoundryServiceBrokerTypes.cs
+++ b/src/Configuration/src/CloudFoundry/ServiceBindings/CloudFoundryServiceBrokerTypes.cs
@@ -10,16 +10,53 @@ namespace Steeltoe.Configuration.CloudFoundry.ServiceBindings;
[Flags]
public enum CloudFoundryServiceBrokerTypes
{
+ ///
+ /// Don't use any of the built-in brokers.
+ ///
None = 0x0,
+ ///
+ /// Use the built-in brokers for Netflix Eureka.
+ ///
Eureka = 0x1,
+
+ ///
+ /// Use the built-in brokers for JWT and OpenID Connect.
+ ///
Identity = 0x2,
+
+ ///
+ /// Use the built-in brokers for MongoDB.
+ ///
MongoDb = 0x4,
+
+ ///
+ /// Use the built-in brokers for MySQL.
+ ///
MySql = 0x8,
+
+ ///
+ /// Use the built-in brokers for PostgreSQL.
+ ///
PostgreSql = 0x10,
+
+ ///
+ /// Use the built-in brokers for RabbitMQ.
+ ///
RabbitMQ = 0x20,
+
+ ///
+ /// Use the built-in brokers for Redis/Valkey.
+ ///
Redis = 0x40,
+
+ ///
+ /// Use the built-in brokers for Microsoft SQL Server.
+ ///
SqlServer = 0x80,
+ ///
+ /// Use all built-in brokers.
+ ///
All = Eureka | Identity | MongoDb | MySql | PostgreSql | RabbitMQ | Redis | SqlServer
}
From 4f5d923d09a14bb6391e0cfe8dc28d19d6943927 Mon Sep 17 00:00:00 2001
From: Bart Koelman <104792814+bart-vmware@users.noreply.github.com>
Date: Fri, 24 Apr 2026 11:11:21 +0200
Subject: [PATCH 7/7] Review feedback: filter already registered
post-processors
---
...oundryServiceBindingConfigurationSource.cs | 7 +++---
.../ConfigurationBuilderExtensions.cs | 23 ++++++++++++++++---
.../ConfigurationBuilderExtensionsTest.cs | 18 +++++++++++++++
3 files changed, 42 insertions(+), 6 deletions(-)
diff --git a/src/Configuration/src/CloudFoundry/ServiceBindings/CloudFoundryServiceBindingConfigurationSource.cs b/src/Configuration/src/CloudFoundry/ServiceBindings/CloudFoundryServiceBindingConfigurationSource.cs
index 049734ab5b..812960c4ce 100644
--- a/src/Configuration/src/CloudFoundry/ServiceBindings/CloudFoundryServiceBindingConfigurationSource.cs
+++ b/src/Configuration/src/CloudFoundry/ServiceBindings/CloudFoundryServiceBindingConfigurationSource.cs
@@ -11,14 +11,15 @@ namespace Steeltoe.Configuration.CloudFoundry.ServiceBindings;
internal sealed class CloudFoundryServiceBindingConfigurationSource : PostProcessorConfigurationSource, IConfigurationSource
{
private readonly IServiceBindingsReader _serviceBindingsReader;
- private readonly CloudFoundryServiceBrokerTypes _brokerTypes;
+
+ public CloudFoundryServiceBrokerTypes BrokerTypes { get; }
public CloudFoundryServiceBindingConfigurationSource(IServiceBindingsReader serviceBindingsReader, CloudFoundryServiceBrokerTypes brokerTypes)
{
ArgumentNullException.ThrowIfNull(serviceBindingsReader);
_serviceBindingsReader = serviceBindingsReader;
- _brokerTypes = brokerTypes;
+ BrokerTypes = brokerTypes;
}
public IConfigurationProvider Build(IConfigurationBuilder builder)
@@ -31,6 +32,6 @@ public IConfigurationProvider Build(IConfigurationBuilder builder)
private string DebuggerToString()
{
- return $"{GetType().FullName} ({_brokerTypes})";
+ return $"{GetType().FullName} ({BrokerTypes})";
}
}
diff --git a/src/Configuration/src/CloudFoundry/ServiceBindings/ConfigurationBuilderExtensions.cs b/src/Configuration/src/CloudFoundry/ServiceBindings/ConfigurationBuilderExtensions.cs
index d5b880eeb1..8cdebbc329 100644
--- a/src/Configuration/src/CloudFoundry/ServiceBindings/ConfigurationBuilderExtensions.cs
+++ b/src/Configuration/src/CloudFoundry/ServiceBindings/ConfigurationBuilderExtensions.cs
@@ -119,9 +119,11 @@ public static IConfigurationBuilder AddCloudFoundryServiceBindings(this IConfigu
ArgumentNullException.ThrowIfNull(ignoreKeyPredicate);
ArgumentNullException.ThrowIfNull(loggerFactory);
- if (brokerTypes != CloudFoundryServiceBrokerTypes.None)
+ CloudFoundryServiceBrokerTypes missingBrokerTypes = GetMissingBrokerTypes(builder, brokerTypes);
+
+ if (missingBrokerTypes != CloudFoundryServiceBrokerTypes.None)
{
- var source = new CloudFoundryServiceBindingConfigurationSource(serviceBindingsReader ?? DefaultReader, brokerTypes)
+ var source = new CloudFoundryServiceBindingConfigurationSource(serviceBindingsReader ?? DefaultReader, missingBrokerTypes)
{
IgnoreKeyPredicate = ignoreKeyPredicate
};
@@ -130,13 +132,28 @@ public static IConfigurationBuilder AddCloudFoundryServiceBindings(this IConfigu
// WebApplicationBuilder immediately builds the configuration provider and loads it, which executes the post-processors.
// Therefore, adding post-processors afterward is a no-op.
- RegisterPostProcessors(source, brokerTypes, loggerFactory);
+ RegisterPostProcessors(source, missingBrokerTypes, loggerFactory);
builder.Add(source);
}
return builder;
}
+ private static CloudFoundryServiceBrokerTypes GetMissingBrokerTypes(IConfigurationBuilder builder, CloudFoundryServiceBrokerTypes brokerTypesRequested)
+ {
+ CloudFoundryServiceBrokerTypes missingBrokerTypes = brokerTypesRequested;
+
+ if (brokerTypesRequested != CloudFoundryServiceBrokerTypes.None)
+ {
+ foreach (CloudFoundryServiceBindingConfigurationSource existingSource in builder.EnumerateSources())
+ {
+ missingBrokerTypes &= ~existingSource.BrokerTypes;
+ }
+ }
+
+ return missingBrokerTypes;
+ }
+
private static void RegisterPostProcessors(CloudFoundryServiceBindingConfigurationSource source, CloudFoundryServiceBrokerTypes brokerTypes,
ILoggerFactory loggerFactory)
{
diff --git a/src/Configuration/test/CloudFoundry.Test/ServiceBindings/ConfigurationBuilderExtensionsTest.cs b/src/Configuration/test/CloudFoundry.Test/ServiceBindings/ConfigurationBuilderExtensionsTest.cs
index 5188ad19ad..672b54db16 100644
--- a/src/Configuration/test/CloudFoundry.Test/ServiceBindings/ConfigurationBuilderExtensionsTest.cs
+++ b/src/Configuration/test/CloudFoundry.Test/ServiceBindings/ConfigurationBuilderExtensionsTest.cs
@@ -68,6 +68,24 @@ public void AddCloudFoundryServiceBindings_RegistersSubsetOfProcessors()
source.PostProcessors.Should().HaveCount(2);
}
+ [Fact]
+ public void AddCloudFoundryServiceBindings_DoesNotAddMultipleSourcesForSamePostProcessor()
+ {
+ var builder = new ConfigurationBuilder();
+ builder.AddCloudFoundryServiceBindings(CloudFoundryServiceBrokerTypes.None);
+ builder.AddCloudFoundryServiceBindings(CloudFoundryServiceBrokerTypes.PostgreSql | CloudFoundryServiceBrokerTypes.MySql);
+ builder.AddCloudFoundryServiceBindings(CloudFoundryServiceBrokerTypes.PostgreSql | CloudFoundryServiceBrokerTypes.SqlServer);
+ builder.AddCloudFoundryServiceBindings(CloudFoundryServiceBrokerTypes.MySql | CloudFoundryServiceBrokerTypes.RabbitMQ);
+ builder.AddCloudFoundryServiceBindings(CloudFoundryServiceBrokerTypes.SqlServer | CloudFoundryServiceBrokerTypes.RabbitMQ);
+
+ CloudFoundryServiceBindingConfigurationSource[] sources = [.. builder.Sources.OfType()];
+
+ sources.Should().HaveCount(3);
+ sources[0].BrokerTypes.Should().Be(CloudFoundryServiceBrokerTypes.PostgreSql | CloudFoundryServiceBrokerTypes.MySql);
+ sources[1].BrokerTypes.Should().Be(CloudFoundryServiceBrokerTypes.SqlServer);
+ sources[2].BrokerTypes.Should().Be(CloudFoundryServiceBrokerTypes.RabbitMQ);
+ }
+
[Fact]
public void AddCloudFoundryServiceBindings_EnvironmentVariableSet_LoadsServiceBindings()
{