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:
parent
cb55973c27
commit
6b095cf533
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
|
|
|||
Loading…
Reference in New Issue