Dispose configuration in WebHost (#9149)

Register the application configuration as a factory to make it dispose
automatically when the service provider gets disposed. This will dispose
the underlying configuration providers and change token registrations.

The host configuration will be disposed implicitly when the chained
configuration provider within the app configuration gets disposed.
This commit is contained in:
Patrick Westerhoff 2019-04-11 16:16:44 +02:00 committed by Chris Ross
parent 28c5ed950b
commit bcad853cbd
2 changed files with 55 additions and 2 deletions

View File

@ -175,6 +175,10 @@ namespace Microsoft.AspNetCore.Hosting
{
host.Initialize();
// resolve configuration explicitly once to mark it as resolved within the
// service provider, ensuring it will be properly disposed with the provider
_ = host.Services.GetService<IConfiguration>();
var logger = host.Services.GetRequiredService<ILogger<WebHost>>();
// Warn about duplicate HostingStartupAssemblies
@ -264,12 +268,13 @@ namespace Microsoft.AspNetCore.Hosting
var builder = new ConfigurationBuilder()
.SetBasePath(_hostingEnvironment.ContentRootPath)
.AddConfiguration(_config);
.AddConfiguration(_config, shouldDisposeConfiguration: true);
_configureAppConfigurationBuilder?.Invoke(_context, builder);
var configuration = builder.Build();
services.AddSingleton<IConfiguration>(configuration);
// register configuration as factory to make it dispose with the service provider
services.AddSingleton<IConfiguration>(_ => configuration);
_context.Configuration = configuration;
var listener = new DiagnosticListener("Microsoft.AspNetCore");

View File

@ -975,6 +975,54 @@ namespace Microsoft.AspNetCore.Hosting
Assert.Contains("ConfigureServices", ex.Message);
}
[Fact]
public void Dispose_DisposesAppConfiguration()
{
var providerMock = new Mock<ConfigurationProvider>().As<IDisposable>();
providerMock.Setup(d => d.Dispose());
var sourceMock = new Mock<IConfigurationSource>();
sourceMock.Setup(s => s.Build(It.IsAny<IConfigurationBuilder>()))
.Returns((ConfigurationProvider)providerMock.Object);
var host = CreateBuilder()
.ConfigureAppConfiguration(configuration =>
{
configuration.Add(sourceMock.Object);
})
.Build();
providerMock.Verify(c => c.Dispose(), Times.Never);
host.Dispose();
providerMock.Verify(c => c.Dispose(), Times.AtLeastOnce());
}
[Fact]
public async Task DisposeAsync_DisposesAppConfiguration()
{
var providerMock = new Mock<ConfigurationProvider>().As<IDisposable>();
providerMock.Setup(d => d.Dispose());
var sourceMock = new Mock<IConfigurationSource>();
sourceMock.Setup(s => s.Build(It.IsAny<IConfigurationBuilder>()))
.Returns((ConfigurationProvider)providerMock.Object);
var host = CreateBuilder()
.ConfigureAppConfiguration(configuration =>
{
configuration.Add(sourceMock.Object);
})
.Build();
providerMock.Verify(c => c.Dispose(), Times.Never);
await ((IAsyncDisposable)host).DisposeAsync();
providerMock.Verify(c => c.Dispose(), Times.AtLeastOnce());
}
public class BadConfigureServicesStartup
{
public void ConfigureServices(IServiceCollection services, int gunk) { }