Skip to content

Commit 8f2fa03

Browse files
davidfowlCopilot
andcommitted
Read ASPIRE_ENVIRONMENT in DistributedApplicationBuilder
Add ASPIRE_-prefixed environment variables as a configuration source in DistributedApplicationBuilder, using the same AddEnvironmentVariables pattern as the core framework uses for DOTNET_-prefixed variables. ASPIRE_ENVIRONMENT is pre-seeded into the ConfigurationManager before HostApplicationBuilder adds DOTNET_ env vars and command-line args, giving the correct priority order: 1. --environment CLI flag (highest) 2. DOTNET_ENVIRONMENT 3. ASPIRE_ENVIRONMENT 4. Default (Production) Tests use RemoteExecutor to run each test in a separate process, avoiding concurrency issues from env var mutation. Fixes #16096 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 598c9d4 commit 8f2fa03

File tree

3 files changed

+102
-0
lines changed

3 files changed

+102
-0
lines changed

src/Aspire.Hosting/DistributedApplicationBuilder.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,13 @@ public DistributedApplicationBuilder(DistributedApplicationOptions options)
185185
// so they're used to initialize some types created immediately, e.g. IHostEnvironment.
186186
innerBuilderOptions.Args = options.Args;
187187

188+
// Pre-seed the configuration with ASPIRE_-prefixed environment variables.
189+
// HostApplicationBuilder will then add DOTNET_-prefixed env vars and command line args on top.
190+
// This gives us the priority order: --environment > DOTNET_ENVIRONMENT > ASPIRE_ENVIRONMENT > default.
191+
var configuration = new ConfigurationManager();
192+
configuration.AddEnvironmentVariables(prefix: "ASPIRE_");
193+
innerBuilderOptions.Configuration = configuration;
194+
188195
LogBuilderConstructing(options, innerBuilderOptions);
189196
_innerBuilder = new HostApplicationBuilder(innerBuilderOptions);
190197

src/Shared/KnownConfigNames.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ internal static class KnownConfigNames
5454
public const string DeveloperCertificateDefaultHttpsTermination = "ASPIRE_DEVELOPER_CERTIFICATE_DEFAULT_HTTPS_TERMINATION";
5555
public const string DcpDeveloperCertificate = "ASPIRE_DCP_USE_DEVELOPER_CERTIFICATE";
5656

57+
public const string AspireEnvironment = "ASPIRE_ENVIRONMENT";
58+
5759
public const string DebugSessionInfo = "DEBUG_SESSION_INFO";
5860
public const string DebugSessionRunMode = "DEBUG_SESSION_RUN_MODE";
5961
public const string DebugSessionPort = "DEBUG_SESSION_PORT";
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using Microsoft.DotNet.RemoteExecutor;
5+
using Microsoft.Extensions.Hosting;
6+
7+
namespace Aspire.Hosting.Tests;
8+
9+
[Trait("Partition", "5")]
10+
public class AspireEnvironmentTests
11+
{
12+
[Fact]
13+
public void AspireEnvironmentSetsBuilderEnvironment()
14+
{
15+
var options = new RemoteInvokeOptions();
16+
options.StartInfo.Environment["ASPIRE_ENVIRONMENT"] = "Staging";
17+
options.StartInfo.Environment.Remove("DOTNET_ENVIRONMENT");
18+
options.StartInfo.Environment.Remove("ASPNETCORE_ENVIRONMENT");
19+
20+
RemoteExecutor.Invoke(static () =>
21+
{
22+
var builder = DistributedApplication.CreateBuilder(new DistributedApplicationOptions { DisableDashboard = true });
23+
Assert.Equal("Staging", builder.Environment.EnvironmentName);
24+
}, options).Dispose();
25+
}
26+
27+
[Fact]
28+
public void DotnetEnvironmentTakesPrecedenceOverAspireEnvironment()
29+
{
30+
var options = new RemoteInvokeOptions();
31+
options.StartInfo.Environment["ASPIRE_ENVIRONMENT"] = "Staging";
32+
options.StartInfo.Environment["DOTNET_ENVIRONMENT"] = "Production";
33+
options.StartInfo.Environment.Remove("ASPNETCORE_ENVIRONMENT");
34+
35+
RemoteExecutor.Invoke(static () =>
36+
{
37+
var builder = DistributedApplication.CreateBuilder(new DistributedApplicationOptions { DisableDashboard = true });
38+
Assert.Equal("Production", builder.Environment.EnvironmentName);
39+
}, options).Dispose();
40+
}
41+
42+
[Fact]
43+
public void EnvironmentFlagTakesPrecedenceOverAspireEnvironment()
44+
{
45+
var options = new RemoteInvokeOptions();
46+
options.StartInfo.Environment["ASPIRE_ENVIRONMENT"] = "Staging";
47+
options.StartInfo.Environment.Remove("DOTNET_ENVIRONMENT");
48+
options.StartInfo.Environment.Remove("ASPNETCORE_ENVIRONMENT");
49+
50+
RemoteExecutor.Invoke(static () =>
51+
{
52+
var builder = DistributedApplication.CreateBuilder(new DistributedApplicationOptions
53+
{
54+
DisableDashboard = true,
55+
Args = ["--environment", "Production"]
56+
});
57+
Assert.Equal("Production", builder.Environment.EnvironmentName);
58+
}, options).Dispose();
59+
}
60+
61+
[Fact]
62+
public void DefaultEnvironmentIsProductionWithNoEnvVars()
63+
{
64+
var options = new RemoteInvokeOptions();
65+
options.StartInfo.Environment.Remove("ASPIRE_ENVIRONMENT");
66+
options.StartInfo.Environment.Remove("DOTNET_ENVIRONMENT");
67+
options.StartInfo.Environment.Remove("ASPNETCORE_ENVIRONMENT");
68+
69+
RemoteExecutor.Invoke(static () =>
70+
{
71+
var builder = DistributedApplication.CreateBuilder(new DistributedApplicationOptions { DisableDashboard = true });
72+
Assert.Equal("Production", builder.Environment.EnvironmentName);
73+
}, options).Dispose();
74+
}
75+
76+
[Fact]
77+
public void AspireEnvironmentSetsCustomEnvironmentName()
78+
{
79+
var options = new RemoteInvokeOptions();
80+
options.StartInfo.Environment["ASPIRE_ENVIRONMENT"] = "Testing";
81+
options.StartInfo.Environment.Remove("DOTNET_ENVIRONMENT");
82+
options.StartInfo.Environment.Remove("ASPNETCORE_ENVIRONMENT");
83+
84+
RemoteExecutor.Invoke(static () =>
85+
{
86+
var builder = DistributedApplication.CreateBuilder(new DistributedApplicationOptions { DisableDashboard = true });
87+
Assert.Equal("Testing", builder.Environment.EnvironmentName);
88+
Assert.False(builder.Environment.IsDevelopment());
89+
Assert.False(builder.Environment.IsProduction());
90+
Assert.True(builder.Environment.IsEnvironment("Testing"));
91+
}, options).Dispose();
92+
}
93+
}

0 commit comments

Comments
 (0)