Allow overriding the hosting service provider (#1325)

- Use the IServiceProviderFactory<IServiceCollection>
- Assert creation and disposal service providers
- Updated the tests to verify that service providers are created and disposed
- Called CreateBuilder even in the default case in case the service collection is modified as part of it.
This commit is contained in:
David Fowler 2018-01-31 16:03:40 -08:00 committed by GitHub
parent cb55973c27
commit 6b095cf533
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 103 additions and 4 deletions

View File

@ -143,9 +143,8 @@ namespace Microsoft.AspNetCore.Hosting.Internal
{
// Get the default factory
var serviceProviderFactory = HostingServiceProvider.GetRequiredService<IServiceProviderFactory<IServiceCollection>>();
// Don't bother calling CreateBuilder since it just returns the default service collection
applicationServiceProvider = serviceProviderFactory.CreateServiceProvider(services);
var builder = serviceProviderFactory.CreateBuilder(services);
applicationServiceProvider = serviceProviderFactory.CreateServiceProvider(builder);
}
return applicationServiceProvider ?? services.BuildServiceProvider();

View File

@ -153,7 +153,7 @@ namespace Microsoft.AspNetCore.Hosting
var hostingServices = BuildCommonServices(out var hostingStartupErrors);
var applicationServices = hostingServices.Clone();
var hostingServiceProvider = hostingServices.BuildServiceProvider();
var hostingServiceProvider = GetProviderFromFactory(hostingServices);
if (!_options.SuppressStatusMessages)
{
@ -202,6 +202,22 @@ namespace Microsoft.AspNetCore.Hosting
host.Dispose();
throw;
}
IServiceProvider GetProviderFromFactory(IServiceCollection collection)
{
var provider = collection.BuildServiceProvider();
var factory = provider.GetService<IServiceProviderFactory<IServiceCollection>>();
if (factory != null)
{
using (provider)
{
return factory.CreateServiceProvider(factory.CreateBuilder(collection));
}
}
return provider;
}
}
private IServiceCollection BuildCommonServices(out AggregateException hostingStartupErrors)

View File

@ -809,6 +809,45 @@ namespace Microsoft.AspNetCore.Hosting
}
}
[Fact]
public async Task ExternalContainerInstanceCanBeUsedForEverything()
{
var disposables = new List<DisposableService>();
var containerFactory = new ExternalContainerFactory(services =>
{
services.AddSingleton(sp =>
{
var service = new DisposableService();
disposables.Add(service);
return service;
});
});
var host = new WebHostBuilder()
.UseStartup<StartupWithExternalServices>()
.UseServer(new TestServer())
.ConfigureServices(services =>
{
services.AddSingleton<IServiceProviderFactory<IServiceCollection>>(containerFactory);
})
.Build();
using (host)
{
await host.StartAsync();
}
// We should create the hosting service provider and the application service provider
Assert.Equal(2, containerFactory.ServiceProviders.Count);
Assert.Equal(2, disposables.Count);
Assert.NotEqual(disposables[0], disposables[1]);
Assert.True(disposables[0].Disposed);
Assert.True(disposables[1].Disposed);
}
[Fact]
public void Build_HostingStartupAssemblyCanBeExcluded()
{
@ -1048,6 +1087,51 @@ namespace Microsoft.AspNetCore.Hosting
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
}
internal class ExternalContainerFactory : IServiceProviderFactory<IServiceCollection>
{
private readonly Action<IServiceCollection> _configureServices;
private readonly List<IServiceProvider> _serviceProviders = new List<IServiceProvider>();
public List<IServiceProvider> ServiceProviders => _serviceProviders;
public ExternalContainerFactory(Action<IServiceCollection> configureServices)
{
_configureServices = configureServices;
}
public IServiceCollection CreateBuilder(IServiceCollection services)
{
_configureServices(services);
return services;
}
public IServiceProvider CreateServiceProvider(IServiceCollection containerBuilder)
{
var provider = containerBuilder.BuildServiceProvider();
_serviceProviders.Add(provider);
return provider;
}
}
internal class StartupWithExternalServices
{
public DisposableService DisposableServiceCtor { get; set; }
public DisposableService DisposableServiceApp { get; set; }
public StartupWithExternalServices(DisposableService disposable)
{
DisposableServiceCtor = disposable;
}
public void ConfigureServices(IServiceCollection services) { }
public void Configure(IApplicationBuilder app, DisposableService disposable)
{
DisposableServiceApp = disposable;
}
}
internal class StartupVerifyServiceA : IStartup
{
internal ServiceA ServiceA { get; set; }