Enable configuring the default service provider (#943)

* Enable configuring the default service provider
- Added UseDefaultServiceProvider method
- Made DelegateStartup use the IServiceProviderFactory. One downside
here is that we can't use 3rd party DI containers with the Configure
delegate since it's hardcoded to the the specific Startup type but that's
not a regression.
This commit is contained in:
David Fowler 2017-02-14 21:25:43 -08:00 committed by GitHub
parent ce5838ac57
commit d57d729d13
3 changed files with 60 additions and 4 deletions

View File

@ -3,14 +3,15 @@
using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
namespace Microsoft.AspNetCore.Hosting
{
public class DelegateStartup : StartupBase
public class DelegateStartup : StartupBase<IServiceCollection>
{
private Action<IApplicationBuilder> _configureApp;
public DelegateStartup(Action<IApplicationBuilder> configureApp)
public DelegateStartup(IServiceProviderFactory<IServiceCollection> factory, Action<IApplicationBuilder> configureApp) : base(factory)
{
_configureApp = configureApp;
}

View File

@ -6,6 +6,7 @@ using System.Reflection;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting.Internal;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
namespace Microsoft.AspNetCore.Hosting
{
@ -29,7 +30,10 @@ namespace Microsoft.AspNetCore.Hosting
return hostBuilder.UseSetting(WebHostDefaults.ApplicationKey, startupAssemblyName)
.ConfigureServices(services =>
{
services.AddSingleton<IStartup>(new DelegateStartup(configureApp));
services.AddSingleton<IStartup>(sp =>
{
return new DelegateStartup(sp.GetRequiredService<IServiceProviderFactory<IServiceCollection>>(), configureApp);
});
});
}
@ -72,5 +76,21 @@ namespace Microsoft.AspNetCore.Hosting
{
return hostBuilder.UseStartup(typeof(TStartup));
}
/// <summary>
/// Configures the default service provider
/// </summary>
/// <param name="hostBuilder">The <see cref="IWebHostBuilder"/> to configure.</param>
/// <param name="configure">A callback used to configure the <see cref="ServiceProviderOptions"/> for the default <see cref="IServiceProvider"/>.</param>
/// <returns>The <see cref="IWebHostBuilder"/>.</returns>
public static IWebHostBuilder UseDefaultServiceProvider(this IWebHostBuilder hostBuilder, Action<ServiceProviderOptions> configure)
{
return hostBuilder.ConfigureServices(services =>
{
var options = new ServiceProviderOptions();
configure(options);
services.Replace(ServiceDescriptor.Singleton<IServiceProviderFactory<IServiceCollection>>(new DefaultServiceProviderFactory(options)));
});
}
}
}

View File

@ -157,6 +157,28 @@ namespace Microsoft.AspNetCore.Hosting
Assert.NotNull(host.Services.GetService<ILoggerFactory>());
}
[Fact]
public void ConfigureDefaultServiceProvider()
{
var hostBuilder = new WebHostBuilder()
.UseServer(new TestServer())
.ConfigureServices(s =>
{
s.AddTransient<ServiceD>();
s.AddScoped<ServiceC>();
})
.Configure(app =>
{
app.ApplicationServices.GetRequiredService<ServiceC>();
})
.UseDefaultServiceProvider(options =>
{
options.ValidateScopes = true;
});
Assert.Throws<InvalidOperationException>(() => hostBuilder.Build());
}
[Fact]
public void UseLoggerFactoryHonored()
{
@ -621,6 +643,19 @@ namespace Microsoft.AspNetCore.Hosting
}
}
private class ServiceC
{
public ServiceC(ServiceD serviceD)
{
}
}
private class ServiceD
{
}
private class ServiceA
{