Skip to content

Commit c6154ba

Browse files
authored
Make UseUrls() override default hosting config (#39836)
1 parent 7c5b80c commit c6154ba

File tree

2 files changed

+44
-4
lines changed

2 files changed

+44
-4
lines changed

src/DefaultBuilder/src/WebApplicationBuilder.cs

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ public sealed class WebApplicationBuilder
2222
private readonly BootstrapHostBuilder _bootstrapHostBuilder;
2323
private readonly WebApplicationServiceCollection _services = new();
2424
private readonly List<KeyValuePair<string, string>> _hostConfigurationValues;
25+
private readonly ConfigurationManager _hostConfigurationManager = new();
2526

2627
private WebApplication? _builtApplication;
2728

@@ -76,6 +77,8 @@ internal WebApplicationBuilder(WebApplicationOptions options, Action<IHostBuilde
7677
});
7778

7879
Configuration = new();
80+
// This is chained as the first configuration source in Configuration so host config can be added later without overriding app config.
81+
Configuration.AddConfiguration(_hostConfigurationManager, shouldDisposeConfiguration: true);
7982

8083
// Collect the hosted services separately since we want those to run after the user's hosted services
8184
_services.TrackHostedServices = true;
@@ -194,22 +197,32 @@ public WebApplication Build()
194197
// to the new one. This allows code that has references to the service collection to still function.
195198
_services.InnerCollection = services;
196199

200+
// Keep any configuration sources added before the TrackingChainedConfigurationSource (namely host configuration from _hostConfigurationValues)
201+
// from overriding config values set via Configuration by inserting them at beginning using _hostConfigurationValues.
202+
var beforeChainedConfig = true;
197203
var hostBuilderProviders = ((IConfigurationRoot)context.Configuration).Providers;
198204

199205
if (!hostBuilderProviders.Contains(chainedConfigSource.BuiltProvider))
200206
{
201207
// Something removed the _hostBuilder's TrackingChainedConfigurationSource pointing back to the ConfigurationManager.
202208
// This is likely a test using WebApplicationFactory. Replicate the effect by clearing the ConfingurationManager sources.
203209
((IConfigurationBuilder)Configuration).Sources.Clear();
210+
beforeChainedConfig = false;
204211
}
205212

206-
// Make builder.Configuration match the final configuration. To do that, we add the additional
207-
// providers in the inner _hostBuilders's Configuration to the ConfigurationManager.
213+
// Make the ConfigurationManager match the final _hostBuilder's configuration. To do that, we add the additional providers
214+
// to the inner _hostBuilders's configuration to the ConfigurationManager. We wrap the existing provider in a
215+
// configuration source to avoid rebuilding or reloading the already added configuration sources.
208216
foreach (var provider in hostBuilderProviders)
209217
{
210-
if (!ReferenceEquals(provider, chainedConfigSource.BuiltProvider))
218+
if (ReferenceEquals(provider, chainedConfigSource.BuiltProvider))
211219
{
212-
((IConfigurationBuilder)Configuration).Add(new ConfigurationProviderSource(provider));
220+
beforeChainedConfig = false;
221+
}
222+
else
223+
{
224+
IConfigurationBuilder configBuilder = beforeChainedConfig ? _hostConfigurationManager : Configuration;
225+
configBuilder.Add(new ConfigurationProviderSource(provider));
213226
}
214227
}
215228
});

src/DefaultBuilder/test/Microsoft.AspNetCore.Tests/WebApplicationTests.cs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,33 @@ public async Task WebApplicationRunUrls_OverridesIServerAddressesFeature()
129129
await runTask;
130130
}
131131

132+
[Fact]
133+
public async Task WebApplicationWebHostUseUrls_OverridesDefaultHostingConfiguration()
134+
{
135+
var builder = new WebApplicationBuilder(new(), bootstrapBuilder =>
136+
{
137+
bootstrapBuilder.ConfigureHostConfiguration(configBuilder =>
138+
{
139+
configBuilder.AddInMemoryCollection(new Dictionary<string, string>
140+
{
141+
[WebHostDefaults.ServerUrlsKey] = "http://localhost:5000",
142+
});
143+
});
144+
});
145+
146+
builder.WebHost.UseUrls("http://localhost:5001");
147+
148+
var urls = new List<string>();
149+
var server = new MockAddressesServer(urls);
150+
builder.Services.AddSingleton<IServer>(server);
151+
await using var app = builder.Build();
152+
153+
await app.StartAsync();
154+
155+
var url = Assert.Single(urls);
156+
Assert.Equal("http://localhost:5001", url);
157+
}
158+
132159
[Fact]
133160
public async Task WebApplicationUrls_ThrowsInvalidOperationExceptionIfThereIsNoIServerAddressesFeature()
134161
{

0 commit comments

Comments
 (0)