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

Commit 6b095cf

Browse files
authored
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.
1 parent cb55973 commit 6b095cf

File tree

3 files changed

+103
-4
lines changed

3 files changed

+103
-4
lines changed

src/Microsoft.AspNetCore.Hosting/Internal/StartupLoader.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -143,9 +143,8 @@ IServiceProvider ConfigureServicesWithContainerConfiguration(IServiceCollection
143143
{
144144
// Get the default factory
145145
var serviceProviderFactory = HostingServiceProvider.GetRequiredService<IServiceProviderFactory<IServiceCollection>>();
146-
147-
// Don't bother calling CreateBuilder since it just returns the default service collection
148-
applicationServiceProvider = serviceProviderFactory.CreateServiceProvider(services);
146+
var builder = serviceProviderFactory.CreateBuilder(services);
147+
applicationServiceProvider = serviceProviderFactory.CreateServiceProvider(builder);
149148
}
150149

151150
return applicationServiceProvider ?? services.BuildServiceProvider();

src/Microsoft.AspNetCore.Hosting/WebHostBuilder.cs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ public IWebHost Build()
153153

154154
var hostingServices = BuildCommonServices(out var hostingStartupErrors);
155155
var applicationServices = hostingServices.Clone();
156-
var hostingServiceProvider = hostingServices.BuildServiceProvider();
156+
var hostingServiceProvider = GetProviderFromFactory(hostingServices);
157157

158158
if (!_options.SuppressStatusMessages)
159159
{
@@ -202,6 +202,22 @@ public IWebHost Build()
202202
host.Dispose();
203203
throw;
204204
}
205+
206+
IServiceProvider GetProviderFromFactory(IServiceCollection collection)
207+
{
208+
var provider = collection.BuildServiceProvider();
209+
var factory = provider.GetService<IServiceProviderFactory<IServiceCollection>>();
210+
211+
if (factory != null)
212+
{
213+
using (provider)
214+
{
215+
return factory.CreateServiceProvider(factory.CreateBuilder(collection));
216+
}
217+
}
218+
219+
return provider;
220+
}
205221
}
206222

207223
private IServiceCollection BuildCommonServices(out AggregateException hostingStartupErrors)

test/Microsoft.AspNetCore.Hosting.Tests/WebHostBuilderTests.cs

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -809,6 +809,45 @@ public void Build_RunsHostingStartupAssembliesBeforeApplication()
809809
}
810810
}
811811

812+
813+
[Fact]
814+
public async Task ExternalContainerInstanceCanBeUsedForEverything()
815+
{
816+
var disposables = new List<DisposableService>();
817+
818+
var containerFactory = new ExternalContainerFactory(services =>
819+
{
820+
services.AddSingleton(sp =>
821+
{
822+
var service = new DisposableService();
823+
disposables.Add(service);
824+
return service;
825+
});
826+
});
827+
828+
var host = new WebHostBuilder()
829+
.UseStartup<StartupWithExternalServices>()
830+
.UseServer(new TestServer())
831+
.ConfigureServices(services =>
832+
{
833+
services.AddSingleton<IServiceProviderFactory<IServiceCollection>>(containerFactory);
834+
})
835+
.Build();
836+
837+
using (host)
838+
{
839+
await host.StartAsync();
840+
}
841+
842+
// We should create the hosting service provider and the application service provider
843+
Assert.Equal(2, containerFactory.ServiceProviders.Count);
844+
Assert.Equal(2, disposables.Count);
845+
846+
Assert.NotEqual(disposables[0], disposables[1]);
847+
Assert.True(disposables[0].Disposed);
848+
Assert.True(disposables[1].Disposed);
849+
}
850+
812851
[Fact]
813852
public void Build_HostingStartupAssemblyCanBeExcluded()
814853
{
@@ -1048,6 +1087,51 @@ public Task StartAsync<TContext>(IHttpApplication<TContext> application, Cancell
10481087
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
10491088
}
10501089

1090+
internal class ExternalContainerFactory : IServiceProviderFactory<IServiceCollection>
1091+
{
1092+
private readonly Action<IServiceCollection> _configureServices;
1093+
private readonly List<IServiceProvider> _serviceProviders = new List<IServiceProvider>();
1094+
1095+
public List<IServiceProvider> ServiceProviders => _serviceProviders;
1096+
1097+
public ExternalContainerFactory(Action<IServiceCollection> configureServices)
1098+
{
1099+
_configureServices = configureServices;
1100+
}
1101+
1102+
public IServiceCollection CreateBuilder(IServiceCollection services)
1103+
{
1104+
_configureServices(services);
1105+
return services;
1106+
}
1107+
1108+
public IServiceProvider CreateServiceProvider(IServiceCollection containerBuilder)
1109+
{
1110+
var provider = containerBuilder.BuildServiceProvider();
1111+
_serviceProviders.Add(provider);
1112+
return provider;
1113+
}
1114+
}
1115+
1116+
internal class StartupWithExternalServices
1117+
{
1118+
public DisposableService DisposableServiceCtor { get; set; }
1119+
1120+
public DisposableService DisposableServiceApp { get; set; }
1121+
1122+
public StartupWithExternalServices(DisposableService disposable)
1123+
{
1124+
DisposableServiceCtor = disposable;
1125+
}
1126+
1127+
public void ConfigureServices(IServiceCollection services) { }
1128+
1129+
public void Configure(IApplicationBuilder app, DisposableService disposable)
1130+
{
1131+
DisposableServiceApp = disposable;
1132+
}
1133+
}
1134+
10511135
internal class StartupVerifyServiceA : IStartup
10521136
{
10531137
internal ServiceA ServiceA { get; set; }

0 commit comments

Comments
 (0)