Skip to content
This repository has been archived by the owner on Dec 19, 2018. It is now read-only.

Commit

Permalink
Allow overriding the hosting service provider (#1325)
Browse files Browse the repository at this point in the history
- 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.
  • Loading branch information
davidfowl authored Feb 1, 2018
1 parent cb55973 commit 6b095cf
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 4 deletions.
5 changes: 2 additions & 3 deletions src/Microsoft.AspNetCore.Hosting/Internal/StartupLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -143,9 +143,8 @@ IServiceProvider ConfigureServicesWithContainerConfiguration(IServiceCollection
{
// 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();
Expand Down
18 changes: 17 additions & 1 deletion src/Microsoft.AspNetCore.Hosting/WebHostBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ public IWebHost Build()

var hostingServices = BuildCommonServices(out var hostingStartupErrors);
var applicationServices = hostingServices.Clone();
var hostingServiceProvider = hostingServices.BuildServiceProvider();
var hostingServiceProvider = GetProviderFromFactory(hostingServices);

if (!_options.SuppressStatusMessages)
{
Expand Down Expand Up @@ -202,6 +202,22 @@ public IWebHost Build()
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)
Expand Down
84 changes: 84 additions & 0 deletions test/Microsoft.AspNetCore.Hosting.Tests/WebHostBuilderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -809,6 +809,45 @@ public void Build_RunsHostingStartupAssembliesBeforeApplication()
}
}


[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()
{
Expand Down Expand Up @@ -1048,6 +1087,51 @@ public Task StartAsync<TContext>(IHttpApplication<TContext> application, Cancell
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; }
Expand Down

0 comments on commit 6b095cf

Please sign in to comment.