Skip to content

Commit 4a1ced1

Browse files
authored
Apply hosting environment via command line args (#34794)
* Apply hosting environment via command line args - This makes sure that the entire applicaton can see changes to host configuration (env, content root etc). - Added tests to verify those scenarios
1 parent 6eaba08 commit 4a1ced1

File tree

4 files changed

+100
-15
lines changed

4 files changed

+100
-15
lines changed

src/Mvc/Mvc.Testing/src/DeferredHostBuilder.cs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ internal class DeferredHostBuilder : IHostBuilder
1919
private Action<IHostBuilder> _configure;
2020
private Func<string[], object>? _hostFactory;
2121

22+
private readonly ConfigurationManager _hostConfiguration = new();
23+
2224
// This task represents a call to IHost.Start, we create it here preemptively in case the application
2325
// exits due to an exception or because it didn't wait for the shutdown signal
2426
private readonly TaskCompletionSource _hostStartTcs = new(TaskCreationOptions.RunContinuationsAsynchronously);
@@ -38,8 +40,18 @@ public DeferredHostBuilder()
3840

3941
public IHost Build()
4042
{
43+
// Hosting configuration is being provided by args so that
44+
// we can impact WebApplicationBuilder based applications.
45+
var args = new List<string>();
46+
47+
// Transform the host configuration into command line arguments
48+
foreach (var (key, value) in _hostConfiguration.AsEnumerable())
49+
{
50+
args.Add($"--{key}={value}");
51+
}
52+
4153
// This will never be null if the case where Build is being called
42-
var host = (IHost)_hostFactory!(Array.Empty<string>());
54+
var host = (IHost)_hostFactory!(args.ToArray());
4355

4456
// We can't return the host directly since we need to defer the call to StartAsync
4557
return new DeferredHost(host, _hostStartTcs);
@@ -59,7 +71,10 @@ public IHostBuilder ConfigureContainer<TContainerBuilder>(Action<HostBuilderCont
5971

6072
public IHostBuilder ConfigureHostConfiguration(Action<IConfigurationBuilder> configureDelegate)
6173
{
62-
_configure += b => b.ConfigureHostConfiguration(configureDelegate);
74+
// Run this immediately so that we can capture the host configuration
75+
// before we pass it to the application. We can do this for app configuration
76+
// as well if it becomes necessary.
77+
configureDelegate(_hostConfiguration);
6378
return this;
6479
}
6580

src/Mvc/Mvc.Testing/src/WebApplicationFactory.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ private void EnsureServer()
159159
if (builder is null)
160160
{
161161
var deferredHostBuilder = new DeferredHostBuilder();
162+
deferredHostBuilder.UseEnvironment(Environments.Development);
162163
// This helper call does the hard work to determine if we can fallback to diagnostic source events to get the host instance
163164
var factory = HostFactoryResolver.ResolveHostFactory(
164165
typeof(TEntryPoint).Assembly,

src/Mvc/test/Mvc.FunctionalTests/SimpleWithWebApplicationBuilderTests.cs

Lines changed: 78 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,37 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
using System.Collections.Generic;
45
using System.Net;
56
using System.Net.Http;
67
using System.Threading.Tasks;
8+
using Microsoft.AspNetCore.Hosting;
9+
using Microsoft.AspNetCore.Mvc.Testing;
10+
using Microsoft.AspNetCore.Testing;
11+
using Microsoft.Extensions.Configuration;
12+
using Microsoft.Extensions.Hosting;
713
using Xunit;
814

915
namespace Microsoft.AspNetCore.Mvc.FunctionalTests
1016
{
1117
public class SimpleWithWebApplicationBuilderTests : IClassFixture<MvcTestFixture<SimpleWebSiteWithWebApplicationBuilder.FakeStartup>>
1218
{
19+
private readonly MvcTestFixture<SimpleWebSiteWithWebApplicationBuilder.FakeStartup> _fixture;
20+
1321
public SimpleWithWebApplicationBuilderTests(MvcTestFixture<SimpleWebSiteWithWebApplicationBuilder.FakeStartup> fixture)
1422
{
15-
Client = fixture.CreateDefaultClient();
23+
_fixture = fixture;
1624
}
1725

18-
public HttpClient Client { get; }
19-
2026
[Fact]
2127
public async Task HelloWorld()
2228
{
2329
// Arrange
2430
var expected = "Hello World";
31+
using var client = _fixture.CreateDefaultClient();
2532

2633
// Act
27-
var content = await Client.GetStringAsync("http://localhost/");
34+
var content = await client.GetStringAsync("http://localhost/");
2835

2936
// Assert
3037
Assert.Equal(expected, content);
@@ -35,9 +42,10 @@ public async Task JsonResult_Works()
3542
{
3643
// Arrange
3744
var expected = "{\"name\":\"John\",\"age\":42}";
45+
using var client = _fixture.CreateDefaultClient();
3846

3947
// Act
40-
var response = await Client.GetAsync("/json");
48+
var response = await client.GetAsync("/json");
4149

4250
// Assert
4351
await response.AssertStatusCodeAsync(HttpStatusCode.OK);
@@ -50,9 +58,10 @@ public async Task OkObjectResult_Works()
5058
{
5159
// Arrange
5260
var expected = "{\"name\":\"John\",\"age\":42}";
61+
using var client = _fixture.CreateDefaultClient();
5362

5463
// Act
55-
var response = await Client.GetAsync("/ok-object");
64+
var response = await client.GetAsync("/ok-object");
5665

5766
// Assert
5867
await response.AssertStatusCodeAsync(HttpStatusCode.OK);
@@ -65,9 +74,10 @@ public async Task AcceptedObjectResult_Works()
6574
{
6675
// Arrange
6776
var expected = "{\"name\":\"John\",\"age\":42}";
77+
using var client = _fixture.CreateDefaultClient();
6878

6979
// Act
70-
var response = await Client.GetAsync("/accepted-object");
80+
var response = await client.GetAsync("/accepted-object");
7181

7282
// Assert
7383
await response.AssertStatusCodeAsync(HttpStatusCode.Accepted);
@@ -79,8 +89,11 @@ public async Task AcceptedObjectResult_Works()
7989
[Fact]
8090
public async Task ActionReturningMoreThanOneResult_NotFound()
8191
{
92+
// Arrange
93+
using var client = _fixture.CreateDefaultClient();
94+
8295
// Act
83-
var response = await Client.GetAsync("/many-results?id=-1");
96+
var response = await client.GetAsync("/many-results?id=-1");
8497

8598
// Assert
8699
await response.AssertStatusCodeAsync(HttpStatusCode.NotFound);
@@ -89,23 +102,75 @@ public async Task ActionReturningMoreThanOneResult_NotFound()
89102
[Fact]
90103
public async Task ActionReturningMoreThanOneResult_Found()
91104
{
105+
// Arrange
106+
using var client = _fixture.CreateDefaultClient();
107+
92108
// Act
93-
var response = await Client.GetAsync("/many-results?id=7");
109+
var response = await client.GetAsync("/many-results?id=7");
94110

95111
// Assert
96112
await response.AssertStatusCodeAsync(HttpStatusCode.MovedPermanently);
97113
Assert.Equal("/json", response.Headers.Location.ToString());
98114
}
99115

100116
[Fact]
101-
public async Task ActionReturningProblemDetails_ConfiguresContentType()
117+
public async Task DefaultEnvironment_Is_Development()
118+
{
119+
// Arrange
120+
var expected = "Development";
121+
using var client = new WebApplicationFactory<SimpleWebSiteWithWebApplicationBuilder.FakeStartup>().CreateClient();
122+
123+
// Act
124+
var content = await client.GetStringAsync("http://localhost/environment");
125+
126+
// Assert
127+
Assert.Equal(expected, content);
128+
}
129+
130+
[Fact]
131+
public async Task Configuration_Can_Be_Overridden()
102132
{
133+
// Arrange
134+
var fixture = _fixture.WithWebHostBuilder(builder =>
135+
{
136+
builder.ConfigureAppConfiguration(builder =>
137+
{
138+
var config = new[]
139+
{
140+
KeyValuePair.Create("Greeting", "Bonjour tout le monde"),
141+
};
142+
143+
builder.AddInMemoryCollection(config);
144+
});
145+
});
146+
147+
var expected = "Bonjour tout le monde";
148+
using var client = fixture.CreateDefaultClient();
149+
103150
// Act
104-
var response = await Client.GetAsync("/problem");
151+
var content = await client.GetStringAsync("http://localhost/greeting");
105152

106153
// Assert
107-
await response.AssertStatusCodeAsync(HttpStatusCode.InternalServerError);
108-
Assert.Equal("application/problem+json", response.Content.Headers.ContentType.ToString());
154+
Assert.Equal(expected, content);
155+
}
156+
157+
[Fact]
158+
public async Task Environment_Can_Be_Overridden()
159+
{
160+
// Arrange
161+
var fixture = _fixture.WithWebHostBuilder(builder =>
162+
{
163+
builder.UseEnvironment(Environments.Staging);
164+
});
165+
166+
var expected = "Staging";
167+
using var client = fixture.CreateDefaultClient();
168+
169+
// Act
170+
var content = await client.GetStringAsync("http://localhost/environment");
171+
172+
// Assert
173+
Assert.Equal(expected, content);
109174
}
110175
}
111176
}

src/Mvc/test/WebSites/SimpleWebSiteWithWebApplicationBuilder/Program.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@
2525

2626
app.MapGet("/problem", () => Results.Problem("Some problem"));
2727

28+
app.MapGet("/environment", (IHostEnvironment environment) => environment.EnvironmentName);
29+
30+
app.MapGet("/greeting", (IConfiguration config) => config["Greeting"]);
31+
2832
app.Run();
2933

3034
record Person(string Name, int Age);

0 commit comments

Comments
 (0)