Add overloads to ConfigureServices to accept the WebHostBuilderContext and make the context accessible in more locations.

This commit is contained in:
glennc 2017-04-13 14:46:33 -07:00 committed by John Luo
parent 0822dd74ac
commit 2b07e88a58
6 changed files with 126 additions and 40 deletions

View File

@ -13,6 +13,15 @@ namespace Microsoft.AspNetCore.Hosting
/// </summary> /// </summary>
public interface IWebHostBuilder public interface IWebHostBuilder
{ {
/// <summary>
/// The <see cref="WebHostBuilderContext"/> used during building.
/// </summary>
/// <remarks>
/// Some properties of this type will be null whilst it is being built, most noteably the <see cref="ILoggerFactory"/> will
/// be null inside the <see cref="ConfigureAppConfiguration(Action{WebHostBuilderContext, IConfigurationBuilder})"/> method.
/// </remarks>
WebHostBuilderContext Context { get; }
/// <summary> /// <summary>
/// Builds an <see cref="IWebHost"/> which hosts a web application. /// Builds an <see cref="IWebHost"/> which hosts a web application.
/// </summary> /// </summary>
@ -32,6 +41,13 @@ namespace Microsoft.AspNetCore.Hosting
/// <returns>The <see cref="IWebHostBuilder"/>.</returns> /// <returns>The <see cref="IWebHostBuilder"/>.</returns>
IWebHostBuilder ConfigureServices(Action<IServiceCollection> configureServices); IWebHostBuilder ConfigureServices(Action<IServiceCollection> configureServices);
/// <summary>
/// Specify the delegate that is used to configure the services of the web application.
/// </summary>
/// <param name="configureServices">The delegate that configures the <see cref="IServiceCollection"/>.</param>
/// <returns>The <see cref="IWebHostBuilder"/>.</returns>
IWebHostBuilder ConfigureServices(Action<WebHostBuilderContext, IServiceCollection> configureServices);
/// <summary> /// <summary>
/// Adds a delegate for configuring the provided <see cref="ILoggerFactory"/>. This may be called multiple times. /// Adds a delegate for configuring the provided <see cref="ILoggerFactory"/>. This may be called multiple times.
/// </summary> /// </summary>
@ -44,7 +60,7 @@ namespace Microsoft.AspNetCore.Hosting
/// </summary> /// </summary>
/// <param name="configureLogging">The delegate that configures the <see cref="ILoggerFactory"/>.</param> /// <param name="configureLogging">The delegate that configures the <see cref="ILoggerFactory"/>.</param>
/// <returns>The <see cref="IWebHostBuilder"/>.</returns> /// <returns>The <see cref="IWebHostBuilder"/>.</returns>
IWebHostBuilder ConfigureLogging<T>(Action<T> configureLogging) where T : ILoggerFactory; IWebHostBuilder ConfigureLogging<T>(Action<WebHostBuilderContext, T> configureLogging) where T : ILoggerFactory;
/// <summary> /// <summary>
/// Add or replace a setting in the configuration. /// Add or replace a setting in the configuration.
@ -75,6 +91,6 @@ namespace Microsoft.AspNetCore.Hosting
/// </summary> /// </summary>
/// <param name="configureDelegate">The delegate for configuring the <see cref="IConfigurationBuilder" /> that will be used to construct an <see cref="IConfiguration" />.</param> /// <param name="configureDelegate">The delegate for configuring the <see cref="IConfigurationBuilder" /> that will be used to construct an <see cref="IConfiguration" />.</param>
/// <returns>The <see cref="IWebHostBuilder"/>.</returns> /// <returns>The <see cref="IWebHostBuilder"/>.</returns>
IWebHostBuilder ConfigureConfiguration(Action<WebHostBuilderContext, IConfigurationBuilder> configureDelegate); IWebHostBuilder ConfigureAppConfiguration(Action<WebHostBuilderContext, IConfigurationBuilder> configureDelegate);
} }
} }

View File

@ -2,7 +2,7 @@
{ {
"OldTypeId": "public interface Microsoft.AspNetCore.Hosting.IWebHostBuilder", "OldTypeId": "public interface Microsoft.AspNetCore.Hosting.IWebHostBuilder",
"NewTypeId": "public interface Microsoft.AspNetCore.Hosting.IWebHostBuilder", "NewTypeId": "public interface Microsoft.AspNetCore.Hosting.IWebHostBuilder",
"NewMemberId": "Microsoft.AspNetCore.Hosting.IWebHostBuilder ConfigureLogging<T0>(System.Action<T0> configureLogging) where T0 : Microsoft.Extensions.Logging.ILoggerFactory", "NewMemberId": "Microsoft.AspNetCore.Hosting.IWebHostBuilder ConfigureLogging<T0>(System.Action<Microsoft.AspNetCore.Hosting.WebHostBuilderContext, T0> configureLogging) where T0 : Microsoft.Extensions.Logging.ILoggerFactory",
"Kind": "Addition" "Kind": "Addition"
}, },
{ {
@ -35,5 +35,17 @@
"NewTypeId": "public interface Microsoft.AspNetCore.Hosting.IWebHost : System.IDisposable", "NewTypeId": "public interface Microsoft.AspNetCore.Hosting.IWebHost : System.IDisposable",
"NewMemberId": "System.Threading.Tasks.Task StopAsync(System.Threading.CancellationToken cancellationToken)", "NewMemberId": "System.Threading.Tasks.Task StopAsync(System.Threading.CancellationToken cancellationToken)",
"Kind": "Addition" "Kind": "Addition"
},
{
"OldTypeId": "public interface Microsoft.AspNetCore.Hosting.IWebHostBuilder",
"NewTypeId": "public interface Microsoft.AspNetCore.Hosting.IWebHostBuilder",
"NewMemberId": "Microsoft.AspNetCore.Hosting.WebHostBuilderContext get_Context()",
"Kind": "Addition"
},
{
"OldTypeId": "public interface Microsoft.AspNetCore.Hosting.IWebHostBuilder",
"NewTypeId": "public interface Microsoft.AspNetCore.Hosting.IWebHostBuilder",
"NewMemberId": "Microsoft.AspNetCore.Hosting.IWebHostBuilder ConfigureServices(System.Action<Microsoft.AspNetCore.Hosting.WebHostBuilderContext, Microsoft.Extensions.DependencyInjection.IServiceCollection> configureServices)",
"Kind": "Addition"
} }
] ]

View File

@ -2,7 +2,7 @@
{ {
"OldTypeId": "public interface Microsoft.AspNetCore.Hosting.IWebHostBuilder", "OldTypeId": "public interface Microsoft.AspNetCore.Hosting.IWebHostBuilder",
"NewTypeId": "public interface Microsoft.AspNetCore.Hosting.IWebHostBuilder", "NewTypeId": "public interface Microsoft.AspNetCore.Hosting.IWebHostBuilder",
"NewMemberId": "Microsoft.AspNetCore.Hosting.IWebHostBuilder ConfigureLogging<T0>(System.Action<T0> configureLogging) where T0 : Microsoft.Extensions.Logging.ILoggerFactory", "NewMemberId": "Microsoft.AspNetCore.Hosting.IWebHostBuilder ConfigureLogging<T0>(System.Action<Microsoft.AspNetCore.Hosting.WebHostBuilderContext, T0> configureLogging) where T0 : Microsoft.Extensions.Logging.ILoggerFactory",
"Kind": "Addition" "Kind": "Addition"
}, },
{ {
@ -14,7 +14,7 @@
{ {
"OldTypeId": "public interface Microsoft.AspNetCore.Hosting.IWebHostBuilder", "OldTypeId": "public interface Microsoft.AspNetCore.Hosting.IWebHostBuilder",
"NewTypeId": "public interface Microsoft.AspNetCore.Hosting.IWebHostBuilder", "NewTypeId": "public interface Microsoft.AspNetCore.Hosting.IWebHostBuilder",
"NewMemberId": "Microsoft.AspNetCore.Hosting.IWebHostBuilder ConfigureConfiguration(System.Action<Microsoft.AspNetCore.Hosting.WebHostBuilderContext, Microsoft.Extensions.Configuration.IConfigurationBuilder> configureDelegate)", "NewMemberId": "Microsoft.AspNetCore.Hosting.IWebHostBuilder ConfigureAppConfiguration(System.Action<Microsoft.AspNetCore.Hosting.WebHostBuilderContext, Microsoft.Extensions.Configuration.IConfigurationBuilder> configureDelegate)",
"Kind": "Addition" "Kind": "Addition"
}, },
{ {
@ -35,5 +35,17 @@
"NewTypeId": "public interface Microsoft.AspNetCore.Hosting.IWebHost : System.IDisposable", "NewTypeId": "public interface Microsoft.AspNetCore.Hosting.IWebHost : System.IDisposable",
"NewMemberId": "System.Threading.Tasks.Task StopAsync(System.Threading.CancellationToken cancellationToken)", "NewMemberId": "System.Threading.Tasks.Task StopAsync(System.Threading.CancellationToken cancellationToken)",
"Kind": "Addition" "Kind": "Addition"
},
{
"OldTypeId": "public interface Microsoft.AspNetCore.Hosting.IWebHostBuilder",
"NewTypeId": "public interface Microsoft.AspNetCore.Hosting.IWebHostBuilder",
"NewMemberId": "Microsoft.AspNetCore.Hosting.WebHostBuilderContext get_Context()",
"Kind": "Addition"
},
{
"OldTypeId": "public interface Microsoft.AspNetCore.Hosting.IWebHostBuilder",
"NewTypeId": "public interface Microsoft.AspNetCore.Hosting.IWebHostBuilder",
"NewMemberId": "Microsoft.AspNetCore.Hosting.IWebHostBuilder ConfigureServices(System.Action<Microsoft.AspNetCore.Hosting.WebHostBuilderContext, Microsoft.Extensions.DependencyInjection.IServiceCollection> configureServices)",
"Kind": "Addition"
} }
] ]

View File

@ -25,14 +25,17 @@ namespace Microsoft.AspNetCore.Hosting
public class WebHostBuilder : IWebHostBuilder public class WebHostBuilder : IWebHostBuilder
{ {
private readonly IHostingEnvironment _hostingEnvironment; private readonly IHostingEnvironment _hostingEnvironment;
private readonly List<Action<IServiceCollection>> _configureServicesDelegates; private readonly List<Action<WebHostBuilderContext, IServiceCollection>> _configureServicesDelegates;
private readonly List<Action<ILoggerFactory>> _configureLoggingDelegates; private readonly List<Action<WebHostBuilderContext, ILoggerFactory>> _configureLoggingDelegates;
private IConfiguration _config; private IConfiguration _config;
private WebHostOptions _options; private WebHostOptions _options;
private bool _webHostBuilt; private bool _webHostBuilt;
private Func<WebHostBuilderContext, ILoggerFactory> _createLoggerFactoryDelegate; private Func<WebHostBuilderContext, ILoggerFactory> _createLoggerFactoryDelegate;
private List<Action<WebHostBuilderContext, IConfigurationBuilder>> _configureConfigurationBuilderDelegates; private List<Action<WebHostBuilderContext, IConfigurationBuilder>> _configureConfigurationBuilderDelegates;
private WebHostBuilderContext _hostingContext;
public WebHostBuilderContext Context { get { return _hostingContext; } }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="WebHostBuilder"/> class. /// Initializes a new instance of the <see cref="WebHostBuilder"/> class.
@ -40,8 +43,8 @@ namespace Microsoft.AspNetCore.Hosting
public WebHostBuilder() public WebHostBuilder()
{ {
_hostingEnvironment = new HostingEnvironment(); _hostingEnvironment = new HostingEnvironment();
_configureServicesDelegates = new List<Action<IServiceCollection>>(); _configureServicesDelegates = new List<Action<WebHostBuilderContext, IServiceCollection>>();
_configureLoggingDelegates = new List<Action<ILoggerFactory>>(); _configureLoggingDelegates = new List<Action<WebHostBuilderContext, ILoggerFactory>>();
_configureConfigurationBuilderDelegates = new List<Action<WebHostBuilderContext, IConfigurationBuilder>>(); _configureConfigurationBuilderDelegates = new List<Action<WebHostBuilderContext, IConfigurationBuilder>>();
_config = new ConfigurationBuilder() _config = new ConfigurationBuilder()
@ -113,6 +116,23 @@ namespace Microsoft.AspNetCore.Hosting
throw new ArgumentNullException(nameof(configureServices)); throw new ArgumentNullException(nameof(configureServices));
} }
_configureServicesDelegates.Add((_, collection) => configureServices(collection));
return this;
}
/// <summary>
/// Adds a delegate for configuring additional services for the host or web application. This may be called
/// multiple times.
/// </summary>
/// <param name="configureServices">A delegate for configuring the <see cref="IServiceCollection"/>.</param>
/// <returns>The <see cref="IWebHostBuilder"/>.</returns>
public IWebHostBuilder ConfigureServices(Action<WebHostBuilderContext, IServiceCollection> configureServices)
{
if (configureServices == null)
{
throw new ArgumentNullException(nameof(configureServices));
}
_configureServicesDelegates.Add(configureServices); _configureServicesDelegates.Add(configureServices);
return this; return this;
} }
@ -129,7 +149,7 @@ namespace Microsoft.AspNetCore.Hosting
throw new ArgumentNullException(nameof(configureLogging)); throw new ArgumentNullException(nameof(configureLogging));
} }
_configureLoggingDelegates.Add(configureLogging); _configureLoggingDelegates.Add((_, factory) => configureLogging(factory));
return this; return this;
} }
@ -155,17 +175,17 @@ namespace Microsoft.AspNetCore.Hosting
/// </summary> /// </summary>
/// <param name="configureLogging">The delegate that configures the <see cref="ILoggerFactory"/>.</param> /// <param name="configureLogging">The delegate that configures the <see cref="ILoggerFactory"/>.</param>
/// <returns>The <see cref="IWebHostBuilder"/>.</returns> /// <returns>The <see cref="IWebHostBuilder"/>.</returns>
public IWebHostBuilder ConfigureLogging<T>(Action<T> configureLogging) where T : ILoggerFactory public IWebHostBuilder ConfigureLogging<T>(Action<WebHostBuilderContext, T> configureLogging) where T : ILoggerFactory
{ {
if (configureLogging == null) if (configureLogging == null)
{ {
throw new ArgumentNullException(nameof(configureLogging)); throw new ArgumentNullException(nameof(configureLogging));
} }
_configureLoggingDelegates.Add(factory => _configureLoggingDelegates.Add((context, factory) =>
{ {
if (factory is T typedFactory) if (factory is T typedFactory)
{ {
configureLogging(typedFactory); configureLogging(context, typedFactory);
} }
}); });
return this; return this;
@ -176,7 +196,7 @@ namespace Microsoft.AspNetCore.Hosting
/// </summary> /// </summary>
/// <param name="configureDelegate">The delegate for configuring the <see cref="IConfigurationBuilder" /> that will be used to construct an <see cref="IConfiguration" />.</param> /// <param name="configureDelegate">The delegate for configuring the <see cref="IConfigurationBuilder" /> that will be used to construct an <see cref="IConfiguration" />.</param>
/// <returns>The <see cref="IWebHostBuilder"/>.</returns> /// <returns>The <see cref="IWebHostBuilder"/>.</returns>
public IWebHostBuilder ConfigureConfiguration(Action<WebHostBuilderContext, IConfigurationBuilder> configureDelegate) public IWebHostBuilder ConfigureAppConfiguration(Action<WebHostBuilderContext, IConfigurationBuilder> configureDelegate)
{ {
if (configureDelegate == null) if (configureDelegate == null)
{ {
@ -241,14 +261,15 @@ namespace Microsoft.AspNetCore.Hosting
var appEnvironment = PlatformServices.Default.Application; var appEnvironment = PlatformServices.Default.Application;
var contentRootPath = ResolveContentRootPath(_options.ContentRootPath, appEnvironment.ApplicationBasePath); var contentRootPath = ResolveContentRootPath(_options.ContentRootPath, appEnvironment.ApplicationBasePath);
var applicationName = _options.ApplicationName ?? appEnvironment.ApplicationName; var applicationName = _options.ApplicationName ?? appEnvironment.ApplicationName;
var hostingContext = new WebHostBuilderContext
_hostingContext = new WebHostBuilderContext
{ {
Configuration = _config Configuration = _config
}; };
// Initialize the hosting environment // Initialize the hosting environment
_hostingEnvironment.Initialize(applicationName, contentRootPath, _options); _hostingEnvironment.Initialize(applicationName, contentRootPath, _options);
hostingContext.HostingEnvironment = _hostingEnvironment; _hostingContext.HostingEnvironment = _hostingEnvironment;
var services = new ServiceCollection(); var services = new ServiceCollection();
services.AddSingleton(_hostingEnvironment); services.AddSingleton(_hostingEnvironment);
@ -259,17 +280,17 @@ namespace Microsoft.AspNetCore.Hosting
foreach (var configureConfiguration in _configureConfigurationBuilderDelegates) foreach (var configureConfiguration in _configureConfigurationBuilderDelegates)
{ {
configureConfiguration(hostingContext, builder); configureConfiguration(_hostingContext, builder);
} }
var configuration = builder.Build(); var configuration = builder.Build();
services.AddSingleton<IConfiguration>(configuration); services.AddSingleton<IConfiguration>(configuration);
hostingContext.Configuration = configuration; _hostingContext.Configuration = configuration;
// The configured ILoggerFactory is added as a singleton here. AddLogging below will not add an additional one. // The configured ILoggerFactory is added as a singleton here. AddLogging below will not add an additional one.
var loggerFactory = _createLoggerFactoryDelegate?.Invoke(hostingContext) ?? new LoggerFactory(configuration.GetSection("Logging")); var loggerFactory = _createLoggerFactoryDelegate?.Invoke(_hostingContext) ?? new LoggerFactory(configuration.GetSection("Logging"));
services.AddSingleton(loggerFactory); services.AddSingleton(loggerFactory);
hostingContext.LoggerFactory = loggerFactory; _hostingContext.LoggerFactory = loggerFactory;
var exceptions = new List<Exception>(); var exceptions = new List<Exception>();
@ -307,7 +328,7 @@ namespace Microsoft.AspNetCore.Hosting
// Kept for back-compat, will remove once ConfigureLogging is removed. // Kept for back-compat, will remove once ConfigureLogging is removed.
foreach (var configureLogging in _configureLoggingDelegates) foreach (var configureLogging in _configureLoggingDelegates)
{ {
configureLogging(loggerFactory); configureLogging(_hostingContext, loggerFactory);
} }
//This is required to add ILogger of T. //This is required to add ILogger of T.
@ -362,7 +383,7 @@ namespace Microsoft.AspNetCore.Hosting
foreach (var configureServices in _configureServicesDelegates) foreach (var configureServices in _configureServicesDelegates)
{ {
configureServices(services); configureServices(_hostingContext, services);
} }
return services; return services;

View File

@ -95,26 +95,28 @@ namespace Microsoft.AspNetCore.Hosting
} }
/// <summary> /// <summary>
/// Configures and use a <see cref="LoggerFactory"/> for the web host. /// Adds a delegate for configuring the provided <see cref="ILoggerFactory"/>. This may be called multiple times.
/// </summary> /// </summary>
/// <param name="hostBuilder">The <see cref="IWebHostBuilder"/> to configure.</param> /// <param name="hostBuilder">The <see cref="IWebHostBuilder" /> to configure.</param>
/// <param name="configure">A callback used to configure the <see cref="LoggerFactory"/> that will be added as a singleton and used by the application.</param> /// <param name="configureLogging">The delegate that configures the <see cref="ILoggerFactory"/>.</param>
/// <returns>The <see cref="IWebHostBuilder"/>.</returns> /// <returns>The <see cref="IWebHostBuilder"/>.</returns>
public static IWebHostBuilder UseLoggerFactory(this IWebHostBuilder hostBuilder, Action<WebHostBuilderContext, LoggerFactory> configure) public static IWebHostBuilder ConfigureLogging(this IWebHostBuilder hostBuilder, Action<WebHostBuilderContext, LoggerFactory> configureLogging)
{ {
if (configure == null) hostBuilder.ConfigureLogging(configureLogging);
{
throw new ArgumentNullException(nameof(configure));
}
hostBuilder.UseLoggerFactory(context =>
{
var loggerFactory = new LoggerFactory();
configure(context, loggerFactory);
return loggerFactory;
});
return hostBuilder; return hostBuilder;
} }
/// <summary>
/// Adds a delegate for configuring the provided <see cref="ILoggerFactory"/>. This may be called multiple times.
/// </summary>
/// <param name="hostBuilder">The <see cref="IWebHostBuilder" /> to configure.</param>
/// <param name="configureLogging">The delegate that configures the <see cref="ILoggerFactory"/>.</param>
/// <returns>The <see cref="IWebHostBuilder"/>.</returns>
public static IWebHostBuilder ConfigureLogging<T>(this IWebHostBuilder hostBuilder, Action<T> configureLogging) where T : ILoggerFactory
{
hostBuilder.ConfigureLogging<T>((_, factory) => configureLogging(factory));
return hostBuilder;
}
} }
} }

View File

@ -257,6 +257,29 @@ namespace Microsoft.AspNetCore.Hosting
Assert.Same(loggerFactory, host.Services.GetService<ILoggerFactory>()); Assert.Same(loggerFactory, host.Services.GetService<ILoggerFactory>());
} }
[Fact]
public void HostingContextCanBeUsed()
{
var hostBuilder = new WebHostBuilder()
.ConfigureAppConfiguration((context, configBuilder) => configBuilder
.AddInMemoryCollection(
new KeyValuePair<string, string>[]
{
new KeyValuePair<string, string>("key1", "value1")
}))
.ConfigureLogging((context, factory) =>
{
Assert.Equal("value1", context.Configuration["key1"]);
})
.UseServer(new TestServer())
.UseStartup<StartupNoServices>();
hostBuilder.Build();
//Verify property on builder is set.
Assert.Equal("value1", hostBuilder.Context.Configuration["key1"]);
}
[Fact] [Fact]
public void ConfigureLoggingCalledIfLoggerFactoryTypeMatches() public void ConfigureLoggingCalledIfLoggerFactoryTypeMatches()
{ {
@ -322,7 +345,7 @@ namespace Microsoft.AspNetCore.Hosting
{ {
var hostBuilder = new WebHostBuilder() var hostBuilder = new WebHostBuilder()
.UseSetting("key1", "value1") .UseSetting("key1", "value1")
.ConfigureConfiguration((context, configBuilder) => .ConfigureAppConfiguration((context, configBuilder) =>
{ {
var config = configBuilder.Build(); var config = configBuilder.Build();
Assert.Equal("value1", config["key1"]); Assert.Equal("value1", config["key1"]);
@ -336,7 +359,7 @@ namespace Microsoft.AspNetCore.Hosting
public void CanConfigureConfigurationAndRetrieveFromDI() public void CanConfigureConfigurationAndRetrieveFromDI()
{ {
var hostBuilder = new WebHostBuilder() var hostBuilder = new WebHostBuilder()
.ConfigureConfiguration((_, configBuilder) => .ConfigureAppConfiguration((_, configBuilder) =>
{ {
configBuilder configBuilder
.AddInMemoryCollection( .AddInMemoryCollection(