From 5a30e22b0d138e1758d941c12ef2e09928cc7628 Mon Sep 17 00:00:00 2001 From: danikishin <68384137+danikishin@users.noreply.github.com> Date: Thu, 28 Mar 2024 04:35:18 +0300 Subject: [PATCH 1/9] Update ResourceBuilderExtensions.cs Allow custom env var names for connection strings Introduce a new WithEnvironment overload in ResourceBuilderExtensions that enables setting a connection string under a custom environment variable name. Fixes #3002. --- .../ResourceBuilderExtensions.cs | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/Aspire.Hosting/ResourceBuilderExtensions.cs b/src/Aspire.Hosting/ResourceBuilderExtensions.cs index d184a26349..884aa43fec 100644 --- a/src/Aspire.Hosting/ResourceBuilderExtensions.cs +++ b/src/Aspire.Hosting/ResourceBuilderExtensions.cs @@ -115,6 +115,33 @@ public static IResourceBuilder WithEnvironment(this IResourceBuilder bu }); } + /// + /// Configures a connection string from a referenced resource builder to be set as an environment variable with a custom name. + /// + /// The destination resource type. + /// The destination resource builder to which the environment variable will be added. + /// The name of the environment variable under which the connection string will be set. + /// The resource builder of the referenced service from which to pull the connection string. + /// The . + public static IResourceBuilder WithEnvironment( + this IResourceBuilder builder, + string envVarName, + IResourceBuilder sourceBuilder) + where T : IResourceWithEnvironment + { + return builder.WithEnvironment(context => + { + var connectionString = sourceBuilder.Resource.GetConnectionString(); + + if (string.IsNullOrEmpty(connectionString)) + { + throw new DistributedApplicationException($"A connection string for '{sourceBuilder.Resource.Name}' could not be retrieved."); + } + + context.EnvironmentVariables[envVarName] = connectionString; + }); + } + /// /// Adds the arguments to be passed to a container resource when the container is started. /// From 652f7f701f5aebd05d2f318a17a1261da94ae5f4 Mon Sep 17 00:00:00 2001 From: danikishin <68384137+danikishin@users.noreply.github.com> Date: Thu, 28 Mar 2024 05:22:22 +0300 Subject: [PATCH 2/9] Update ResourceBuilderExtensions.cs --- src/Aspire.Hosting/ResourceBuilderExtensions.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Aspire.Hosting/ResourceBuilderExtensions.cs b/src/Aspire.Hosting/ResourceBuilderExtensions.cs index 884aa43fec..6ce09ce779 100644 --- a/src/Aspire.Hosting/ResourceBuilderExtensions.cs +++ b/src/Aspire.Hosting/ResourceBuilderExtensions.cs @@ -124,14 +124,14 @@ public static IResourceBuilder WithEnvironment(this IResourceBuilder bu /// The resource builder of the referenced service from which to pull the connection string. /// The . public static IResourceBuilder WithEnvironment( - this IResourceBuilder builder, - string envVarName, - IResourceBuilder sourceBuilder) + this IResourceBuilder builder, + string envVarName, + IResourceBuilder sourceBuilder) where T : IResourceWithEnvironment { - return builder.WithEnvironment(context => + return builder.WithEnvironment(async context => { - var connectionString = sourceBuilder.Resource.GetConnectionString(); + var connectionString = await sourceBuilder.Resource.GetConnectionStringAsync().ConfigureAwait(true); if (string.IsNullOrEmpty(connectionString)) { From 563166b7cc5a56ca711868110824b3be1d68a538 Mon Sep 17 00:00:00 2001 From: danikishin <68384137+danikishin@users.noreply.github.com> Date: Thu, 28 Mar 2024 05:49:08 +0300 Subject: [PATCH 3/9] Update ResourceBuilderExtensions.cs --- src/Aspire.Hosting/ResourceBuilderExtensions.cs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/Aspire.Hosting/ResourceBuilderExtensions.cs b/src/Aspire.Hosting/ResourceBuilderExtensions.cs index 6ce09ce779..d6d58887a0 100644 --- a/src/Aspire.Hosting/ResourceBuilderExtensions.cs +++ b/src/Aspire.Hosting/ResourceBuilderExtensions.cs @@ -131,14 +131,7 @@ public static IResourceBuilder WithEnvironment( { return builder.WithEnvironment(async context => { - var connectionString = await sourceBuilder.Resource.GetConnectionStringAsync().ConfigureAwait(true); - - if (string.IsNullOrEmpty(connectionString)) - { - throw new DistributedApplicationException($"A connection string for '{sourceBuilder.Resource.Name}' could not be retrieved."); - } - - context.EnvironmentVariables[envVarName] = connectionString; + context.EnvironmentVariables[envVarName] = new ConnectionStringReference(sourceBuilder.Resource, optional: false); }); } From 60d404faa25364c6dbec34c992c004b54e868074 Mon Sep 17 00:00:00 2001 From: David Fowler Date: Wed, 27 Mar 2024 20:11:34 -0700 Subject: [PATCH 4/9] Update src/Aspire.Hosting/ResourceBuilderExtensions.cs --- src/Aspire.Hosting/ResourceBuilderExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Aspire.Hosting/ResourceBuilderExtensions.cs b/src/Aspire.Hosting/ResourceBuilderExtensions.cs index d6d58887a0..73ca9fe8cf 100644 --- a/src/Aspire.Hosting/ResourceBuilderExtensions.cs +++ b/src/Aspire.Hosting/ResourceBuilderExtensions.cs @@ -129,7 +129,7 @@ public static IResourceBuilder WithEnvironment( IResourceBuilder sourceBuilder) where T : IResourceWithEnvironment { - return builder.WithEnvironment(async context => + return builder.WithEnvironment(context => { context.EnvironmentVariables[envVarName] = new ConnectionStringReference(sourceBuilder.Resource, optional: false); }); From f8ca2780a5c5a02052ae1112fbb9c435368472c3 Mon Sep 17 00:00:00 2001 From: danikishin Date: Thu, 28 Mar 2024 06:21:01 +0300 Subject: [PATCH 5/9] Remove async keyword --- src/Aspire.Hosting/ResourceBuilderExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Aspire.Hosting/ResourceBuilderExtensions.cs b/src/Aspire.Hosting/ResourceBuilderExtensions.cs index d6d58887a0..73ca9fe8cf 100644 --- a/src/Aspire.Hosting/ResourceBuilderExtensions.cs +++ b/src/Aspire.Hosting/ResourceBuilderExtensions.cs @@ -129,7 +129,7 @@ public static IResourceBuilder WithEnvironment( IResourceBuilder sourceBuilder) where T : IResourceWithEnvironment { - return builder.WithEnvironment(async context => + return builder.WithEnvironment(context => { context.EnvironmentVariables[envVarName] = new ConnectionStringReference(sourceBuilder.Resource, optional: false); }); From 38b6ea372433e59998a063b5446f036a2729177a Mon Sep 17 00:00:00 2001 From: danikishin Date: Thu, 28 Mar 2024 06:21:06 +0300 Subject: [PATCH 6/9] Added unit tests to verify the behavior of the WithEnvironment method --- .../WithEnvironmentTests.cs | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tests/Aspire.Hosting.Tests/WithEnvironmentTests.cs b/tests/Aspire.Hosting.Tests/WithEnvironmentTests.cs index f119636969..bc58153572 100644 --- a/tests/Aspire.Hosting.Tests/WithEnvironmentTests.cs +++ b/tests/Aspire.Hosting.Tests/WithEnvironmentTests.cs @@ -171,6 +171,28 @@ public async Task EnvironmentVariableExpressions() Assert.Equal("{test.connectionString};name=1", manifestConfig["HOST"]); } + [Fact] + public async Task EnvironmentWithConnectionStringSetsProperEnvironmentVariable() + { + // Arrange + const string sourceCon = "sourceConnectionString"; + using var testProgram = CreateTestProgram(); + var sourceBuilder = testProgram.AppBuilder.AddResource(new TestResource("sourceService", sourceCon)); + var targetBuilder = testProgram.AppBuilder.AddContainer("targetContainer", "targetImage"); + + string envVarName = "CUSTOM_CONNECTION_STRING"; + + // Act + targetBuilder.WithEnvironment(envVarName, sourceBuilder); + testProgram.Build(); + + // Call environment variable callbacks with the Publish operation. + var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(targetBuilder.Resource, DistributedApplicationOperation.Publish); + + // Assert + Assert.Single(config, kvp => kvp.Key == envVarName && kvp.Value == "{sourceService.connectionString}"); + } + private sealed class TestResource(string name, string connectionString) : Resource(name), IResourceWithConnectionString { public ReferenceExpression ConnectionStringExpression => From d98d88c8ec28672a456d0d3c946441f5d9e5e9d7 Mon Sep 17 00:00:00 2001 From: danikishin Date: Thu, 28 Mar 2024 06:28:43 +0300 Subject: [PATCH 7/9] typo fix --- src/Aspire.Hosting/ResourceBuilderExtensions.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Aspire.Hosting/ResourceBuilderExtensions.cs b/src/Aspire.Hosting/ResourceBuilderExtensions.cs index 73ca9fe8cf..a53de993f1 100644 --- a/src/Aspire.Hosting/ResourceBuilderExtensions.cs +++ b/src/Aspire.Hosting/ResourceBuilderExtensions.cs @@ -121,17 +121,17 @@ public static IResourceBuilder WithEnvironment(this IResourceBuilder bu /// The destination resource type. /// The destination resource builder to which the environment variable will be added. /// The name of the environment variable under which the connection string will be set. - /// The resource builder of the referenced service from which to pull the connection string. + /// The resource builder of the referenced service from which to pull the connection string. /// The . public static IResourceBuilder WithEnvironment( this IResourceBuilder builder, string envVarName, - IResourceBuilder sourceBuilder) + IResourceBuilder resource) where T : IResourceWithEnvironment { return builder.WithEnvironment(context => { - context.EnvironmentVariables[envVarName] = new ConnectionStringReference(sourceBuilder.Resource, optional: false); + context.EnvironmentVariables[envVarName] = new ConnectionStringReference(resource.Resource, optional: false); }); } From 448e01133f887a89814bcf0bfba34e05d4c85783 Mon Sep 17 00:00:00 2001 From: danikishin Date: Thu, 28 Mar 2024 06:39:12 +0300 Subject: [PATCH 8/9] verify the behavior of the WithEnvironment extension method in run mode --- tests/Aspire.Hosting.Tests/WithEnvironmentTests.cs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/tests/Aspire.Hosting.Tests/WithEnvironmentTests.cs b/tests/Aspire.Hosting.Tests/WithEnvironmentTests.cs index bc58153572..cd8ab89f08 100644 --- a/tests/Aspire.Hosting.Tests/WithEnvironmentTests.cs +++ b/tests/Aspire.Hosting.Tests/WithEnvironmentTests.cs @@ -186,11 +186,17 @@ public async Task EnvironmentWithConnectionStringSetsProperEnvironmentVariable() targetBuilder.WithEnvironment(envVarName, sourceBuilder); testProgram.Build(); - // Call environment variable callbacks with the Publish operation. - var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(targetBuilder.Resource, DistributedApplicationOperation.Publish); + // Call environment variable callbacks for the Run operation. + var runConfig = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(targetBuilder.Resource, DistributedApplicationOperation.Run); // Assert - Assert.Single(config, kvp => kvp.Key == envVarName && kvp.Value == "{sourceService.connectionString}"); + Assert.Single(runConfig, kvp => kvp.Key == envVarName && kvp.Value == sourceCon); + + // Call environment variable callbacks for the Publish operation. + var publishConfig = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(targetBuilder.Resource, DistributedApplicationOperation.Publish); + + // Assert + Assert.Single(publishConfig, kvp => kvp.Key == envVarName && kvp.Value == "{sourceService.connectionString}"); } private sealed class TestResource(string name, string connectionString) : Resource(name), IResourceWithConnectionString From abca904be9ff903174c546b29414ee47843181da Mon Sep 17 00:00:00 2001 From: David Fowler Date: Fri, 29 Mar 2024 01:44:42 -0700 Subject: [PATCH 9/9] Apply suggestions from code review --- src/Aspire.Hosting/ResourceBuilderExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Aspire.Hosting/ResourceBuilderExtensions.cs b/src/Aspire.Hosting/ResourceBuilderExtensions.cs index a53de993f1..fe351bc5da 100644 --- a/src/Aspire.Hosting/ResourceBuilderExtensions.cs +++ b/src/Aspire.Hosting/ResourceBuilderExtensions.cs @@ -116,7 +116,7 @@ public static IResourceBuilder WithEnvironment(this IResourceBuilder bu } /// - /// Configures a connection string from a referenced resource builder to be set as an environment variable with a custom name. + /// Adds an environment variable to the resource with the connection string from the referenced resource. /// /// The destination resource type. /// The destination resource builder to which the environment variable will be added.