diff --git a/eng/Dependencies.props b/eng/Dependencies.props
index 0559d5234d..53312853da 100644
--- a/eng/Dependencies.props
+++ b/eng/Dependencies.props
@@ -19,25 +19,33 @@
+
+
+
+
+
+
+
+
@@ -45,16 +53,20 @@
+
+
+
+
diff --git a/src/Hosting/Hosting/src/GenericHost/GenericWebHostApplicationLifetime.cs b/src/Hosting/Hosting/src/GenericHost/GenericWebHostApplicationLifetime.cs
new file mode 100644
index 0000000000..d95704154e
--- /dev/null
+++ b/src/Hosting/Hosting/src/GenericHost/GenericWebHostApplicationLifetime.cs
@@ -0,0 +1,24 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.Threading;
+
+namespace Microsoft.AspNetCore.Hosting.Internal
+{
+ internal class GenericWebHostApplicationLifetime : IApplicationLifetime
+ {
+ private readonly Microsoft.Extensions.Hosting.IApplicationLifetime _applicationLifetime;
+ public GenericWebHostApplicationLifetime(Microsoft.Extensions.Hosting.IApplicationLifetime applicationLifetime)
+ {
+ _applicationLifetime = applicationLifetime;
+ }
+
+ public CancellationToken ApplicationStarted => _applicationLifetime.ApplicationStarted;
+
+ public CancellationToken ApplicationStopping => _applicationLifetime.ApplicationStopping;
+
+ public CancellationToken ApplicationStopped => _applicationLifetime.ApplicationStopped;
+
+ public void StopApplication() => _applicationLifetime.StopApplication();
+ }
+}
diff --git a/src/Hosting/Hosting/src/GenericHost/GenericWebHostBuilder.cs b/src/Hosting/Hosting/src/GenericHost/GenericWebHostBuilder.cs
new file mode 100644
index 0000000000..6a425883ea
--- /dev/null
+++ b/src/Hosting/Hosting/src/GenericHost/GenericWebHostBuilder.cs
@@ -0,0 +1,376 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Reflection;
+using System.Runtime.ExceptionServices;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting.Builder;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.DependencyInjection.Extensions;
+using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.ObjectPool;
+
+namespace Microsoft.AspNetCore.Hosting.Internal
+{
+ internal class GenericWebHostBuilder : IWebHostBuilder, ISupportsStartup, ISupportsUseDefaultServiceProvider
+ {
+ private readonly IHostBuilder _builder;
+ private readonly IConfiguration _config;
+ private readonly object _startupKey = new object();
+
+ private AggregateException _hostingStartupErrors;
+ private HostingStartupWebHostBuilder _hostingStartupWebHostBuilder;
+
+ public GenericWebHostBuilder(IHostBuilder builder)
+ {
+ _builder = builder;
+
+ _config = new ConfigurationBuilder()
+ .AddEnvironmentVariables(prefix: "ASPNETCORE_")
+ .Build();
+
+ _builder.ConfigureHostConfiguration(config =>
+ {
+ config.AddConfiguration(_config);
+
+ // We do this super early but still late enough that we can process the configuration
+ // wired up by calls to UseSetting
+ ExecuteHostingStartups();
+ });
+
+ // IHostingStartup needs to be executed before any direct methods on the builder
+ // so register these callbacks first
+ _builder.ConfigureAppConfiguration((context, configurationBuilder) =>
+ {
+ if (_hostingStartupWebHostBuilder != null)
+ {
+ var webhostContext = GetWebHostBuilderContext(context);
+ _hostingStartupWebHostBuilder.ConfigureAppConfiguration(webhostContext, configurationBuilder);
+ }
+ });
+
+ _builder.ConfigureServices((context, services) =>
+ {
+ if (_hostingStartupWebHostBuilder != null)
+ {
+ var webhostContext = GetWebHostBuilderContext(context);
+ _hostingStartupWebHostBuilder.ConfigureServices(webhostContext, services);
+ }
+ });
+
+ _builder.ConfigureServices((context, services) =>
+ {
+ var webhostContext = GetWebHostBuilderContext(context);
+ var webHostOptions = (WebHostOptions)context.Properties[typeof(WebHostOptions)];
+
+ // Add the IHostingEnvironment and IApplicationLifetime from Microsoft.AspNetCore.Hosting
+ services.AddSingleton(webhostContext.HostingEnvironment);
+ services.AddSingleton();
+
+ services.Configure(options =>
+ {
+ // Set the options
+ options.WebHostOptions = webHostOptions;
+ // Store and forward any startup errors
+ options.HostingStartupExceptions = _hostingStartupErrors;
+ });
+
+ services.AddHostedService();
+
+ // REVIEW: This is bad since we don't own this type. Anybody could add one of these and it would mess things up
+ // We need to flow this differently
+ var listener = new DiagnosticListener("Microsoft.AspNetCore");
+ services.TryAddSingleton(listener);
+ services.TryAddSingleton(listener);
+
+ services.TryAddSingleton();
+ services.TryAddScoped();
+ services.TryAddSingleton();
+
+ // Conjure up a RequestServices
+ services.TryAddTransient();
+
+ // Ensure object pooling is available everywhere.
+ services.TryAddSingleton();
+
+ // Support UseStartup(assemblyName)
+ if (!string.IsNullOrEmpty(webHostOptions.StartupAssembly))
+ {
+ try
+ {
+ var startupType = StartupLoader.FindStartupType(webHostOptions.StartupAssembly, webhostContext.HostingEnvironment.EnvironmentName);
+ UseStartup(startupType, context, services);
+ }
+ catch (Exception ex) when (webHostOptions.CaptureStartupErrors)
+ {
+ var capture = ExceptionDispatchInfo.Capture(ex);
+
+ services.Configure(options =>
+ {
+ options.ConfigureApplication = app =>
+ {
+ // Throw if there was any errors initializing startup
+ capture.Throw();
+ };
+ });
+ }
+ }
+ });
+ }
+
+ private void ExecuteHostingStartups()
+ {
+ var webHostOptions = new WebHostOptions(_config, Assembly.GetEntryAssembly()?.GetName().Name);
+
+ if (webHostOptions.PreventHostingStartup)
+ {
+ return;
+ }
+
+ var exceptions = new List();
+ _hostingStartupWebHostBuilder = new HostingStartupWebHostBuilder(this);
+
+ // Execute the hosting startup assemblies
+ foreach (var assemblyName in webHostOptions.GetFinalHostingStartupAssemblies().Distinct(StringComparer.OrdinalIgnoreCase))
+ {
+ try
+ {
+ var assembly = Assembly.Load(new AssemblyName(assemblyName));
+
+ foreach (var attribute in assembly.GetCustomAttributes())
+ {
+ var hostingStartup = (IHostingStartup)Activator.CreateInstance(attribute.HostingStartupType);
+ hostingStartup.Configure(_hostingStartupWebHostBuilder);
+ }
+ }
+ catch (Exception ex)
+ {
+ // Capture any errors that happen during startup
+ exceptions.Add(new InvalidOperationException($"Startup assembly {assemblyName} failed to execute. See the inner exception for more details.", ex));
+ }
+ }
+
+ if (exceptions.Count > 0)
+ {
+ _hostingStartupErrors = new AggregateException(exceptions);
+ }
+ }
+
+ public IWebHost Build()
+ {
+ throw new NotSupportedException($"Building this implementation of {nameof(IWebHostBuilder)} is not supported.");
+ }
+
+ public IWebHostBuilder ConfigureAppConfiguration(Action configureDelegate)
+ {
+ _builder.ConfigureAppConfiguration((context, builder) =>
+ {
+ var webhostBuilderContext = GetWebHostBuilderContext(context);
+ configureDelegate(webhostBuilderContext, builder);
+ });
+
+ return this;
+ }
+
+ public IWebHostBuilder ConfigureServices(Action configureServices)
+ {
+ return ConfigureServices((context, services) => configureServices(services));
+ }
+
+ public IWebHostBuilder ConfigureServices(Action configureServices)
+ {
+ _builder.ConfigureServices((context, builder) =>
+ {
+ var webhostBuilderContext = GetWebHostBuilderContext(context);
+ configureServices(webhostBuilderContext, builder);
+ });
+
+ return this;
+ }
+
+ public IWebHostBuilder UseDefaultServiceProvider(Action configure)
+ {
+ // REVIEW: This is a hack to change the builder with the HostBuilderContext in scope,
+ // we're not actually using configuration here
+ _builder.ConfigureAppConfiguration((context, _) =>
+ {
+ var webHostBuilderContext = GetWebHostBuilderContext(context);
+ var options = new ServiceProviderOptions();
+ configure(webHostBuilderContext, options);
+
+ // This is only fine because this runs last
+ _builder.UseServiceProviderFactory(new DefaultServiceProviderFactory(options));
+ });
+
+ return this;
+ }
+
+ public IWebHostBuilder UseStartup(Type startupType)
+ {
+ _builder.ConfigureServices((context, services) =>
+ {
+ UseStartup(startupType, context, services);
+ });
+
+ return this;
+ }
+
+ private void UseStartup(Type startupType, HostBuilderContext context, IServiceCollection services)
+ {
+ var webHostBuilderContext = GetWebHostBuilderContext(context);
+ var webHostOptions = (WebHostOptions)context.Properties[typeof(WebHostOptions)];
+
+ ExceptionDispatchInfo startupError = null;
+ object instance = null;
+ ConfigureBuilder configureBuilder = null;
+
+ try
+ {
+ // We cannot support methods that return IServiceProvider as that is terminal and we need ConfigureServices to compose
+ if (typeof(IStartup).IsAssignableFrom(startupType))
+ {
+ throw new NotSupportedException($"{typeof(IStartup)} isn't supported");
+ }
+
+ instance = ActivatorUtilities.CreateInstance(new HostServiceProvider(webHostBuilderContext), startupType);
+ context.Properties[_startupKey] = instance;
+
+ // Startup.ConfigureServices
+ var configureServicesBuilder = StartupLoader.FindConfigureServicesDelegate(startupType, context.HostingEnvironment.EnvironmentName);
+ var configureServices = configureServicesBuilder.Build(instance);
+
+ configureServices(services);
+
+ // REVIEW: We're doing this in the callback so that we have access to the hosting environment
+ // Startup.ConfigureContainer
+ var configureContainerBuilder = StartupLoader.FindConfigureContainerDelegate(startupType, context.HostingEnvironment.EnvironmentName);
+ if (configureContainerBuilder.MethodInfo != null)
+ {
+ var containerType = configureContainerBuilder.GetContainerType();
+ // Store the builder in the property bag
+ _builder.Properties[typeof(ConfigureContainerBuilder)] = configureContainerBuilder;
+
+ var actionType = typeof(Action<,>).MakeGenericType(typeof(HostBuilderContext), containerType);
+
+ // Get the private ConfigureContainer method on this type then close over the container type
+ var configureCallback = GetType().GetMethod(nameof(ConfigureContainer), BindingFlags.NonPublic | BindingFlags.Instance)
+ .MakeGenericMethod(containerType)
+ .CreateDelegate(actionType, this);
+
+ // _builder.ConfigureContainer(ConfigureContainer);
+ typeof(IHostBuilder).GetMethods().First(m => m.Name == nameof(IHostBuilder.ConfigureContainer))
+ .MakeGenericMethod(containerType)
+ .Invoke(_builder, new object[] { configureCallback });
+ }
+
+ // Resolve Configure after calling ConfigureServices and ConfigureContainer
+ configureBuilder = StartupLoader.FindConfigureDelegate(startupType, context.HostingEnvironment.EnvironmentName);
+ }
+ catch (Exception ex) when (webHostOptions.CaptureStartupErrors)
+ {
+ startupError = ExceptionDispatchInfo.Capture(ex);
+ }
+
+ // Startup.Configure
+ services.Configure(options =>
+ {
+ options.ConfigureApplication = app =>
+ {
+ // Throw if there was any errors initializing startup
+ startupError?.Throw();
+
+ // Execute Startup.Configure
+ if (instance != null && configureBuilder != null)
+ {
+ configureBuilder.Build(instance)(app);
+ }
+ };
+ });
+ }
+
+ private void ConfigureContainer(HostBuilderContext context, TContainer container)
+ {
+ var instance = context.Properties[_startupKey];
+ var builder = (ConfigureContainerBuilder)context.Properties[typeof(ConfigureContainerBuilder)];
+ builder.Build(instance)(container);
+ }
+
+ public IWebHostBuilder Configure(Action configure)
+ {
+ _builder.ConfigureServices((context, services) =>
+ {
+ services.Configure(options =>
+ {
+ options.ConfigureApplication = configure;
+ });
+ });
+
+ return this;
+ }
+
+ private WebHostBuilderContext GetWebHostBuilderContext(HostBuilderContext context)
+ {
+ if (!context.Properties.TryGetValue(typeof(WebHostBuilderContext), out var contextVal))
+ {
+ var options = new WebHostOptions(context.Configuration, Assembly.GetEntryAssembly()?.GetName().Name);
+ var hostingEnvironment = new HostingEnvironment();
+ hostingEnvironment.Initialize(context.HostingEnvironment.ContentRootPath, options);
+
+ var webHostBuilderContext = new WebHostBuilderContext
+ {
+ Configuration = context.Configuration,
+ HostingEnvironment = hostingEnvironment
+ };
+ context.Properties[typeof(WebHostBuilderContext)] = webHostBuilderContext;
+ context.Properties[typeof(WebHostOptions)] = options;
+ return webHostBuilderContext;
+ }
+
+ return (WebHostBuilderContext)contextVal;
+ }
+
+ public string GetSetting(string key)
+ {
+ return _config[key];
+ }
+
+ public IWebHostBuilder UseSetting(string key, string value)
+ {
+ _config[key] = value;
+ return this;
+ }
+
+ // This exists just so that we can use ActivatorUtilities.CreateInstance on the Startup class
+ private class HostServiceProvider : IServiceProvider
+ {
+ private readonly WebHostBuilderContext _context;
+
+ public HostServiceProvider(WebHostBuilderContext context)
+ {
+ _context = context;
+ }
+
+ public object GetService(Type serviceType)
+ {
+ // The implementation of the HostingEnvironment supports both interfaces
+ if (serviceType == typeof(Microsoft.AspNetCore.Hosting.IHostingEnvironment) || serviceType == typeof(IHostingEnvironment))
+ {
+ return _context.HostingEnvironment;
+ }
+
+ if (serviceType == typeof(IConfiguration))
+ {
+ return _context.Configuration;
+ }
+
+ return null;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Hosting/Hosting/src/GenericHost/GenericWebHostServiceOptions.cs b/src/Hosting/Hosting/src/GenericHost/GenericWebHostServiceOptions.cs
new file mode 100644
index 0000000000..715c43514e
--- /dev/null
+++ b/src/Hosting/Hosting/src/GenericHost/GenericWebHostServiceOptions.cs
@@ -0,0 +1,17 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using Microsoft.AspNetCore.Builder;
+
+namespace Microsoft.AspNetCore.Hosting.Internal
+{
+ internal class GenericWebHostServiceOptions
+ {
+ public Action ConfigureApplication { get; set; }
+
+ public WebHostOptions WebHostOptions { get; set; }
+
+ public AggregateException HostingStartupExceptions { get; set; }
+ }
+}
diff --git a/src/Hosting/Hosting/src/GenericHost/GenericWebHostedService.cs b/src/Hosting/Hosting/src/GenericHost/GenericWebHostedService.cs
new file mode 100644
index 0000000000..8ec39059f0
--- /dev/null
+++ b/src/Hosting/Hosting/src/GenericHost/GenericWebHostedService.cs
@@ -0,0 +1,201 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting.Builder;
+using Microsoft.AspNetCore.Hosting.Server;
+using Microsoft.AspNetCore.Hosting.Server.Features;
+using Microsoft.AspNetCore.Hosting.Views;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+using Microsoft.Extensions.StackTrace.Sources;
+
+namespace Microsoft.AspNetCore.Hosting.Internal
+{
+ internal class GenericWebHostService : IHostedService
+ {
+ public GenericWebHostService(IOptions options,
+ IServer server,
+ ILogger logger,
+ DiagnosticListener diagnosticListener,
+ IHttpContextFactory httpContextFactory,
+ IApplicationBuilderFactory applicationBuilderFactory,
+ IEnumerable startupFilters,
+ IConfiguration configuration,
+ IHostingEnvironment hostingEnvironment)
+ {
+ Options = options.Value;
+ Server = server;
+ Logger = logger;
+ DiagnosticListener = diagnosticListener;
+ HttpContextFactory = httpContextFactory;
+ ApplicationBuilderFactory = applicationBuilderFactory;
+ StartupFilters = startupFilters;
+ Configuration = configuration;
+ HostingEnvironment = hostingEnvironment;
+ }
+
+ public GenericWebHostServiceOptions Options { get; }
+ public IServer Server { get; }
+ public ILogger Logger { get; }
+ public DiagnosticListener DiagnosticListener { get; }
+ public IHttpContextFactory HttpContextFactory { get; }
+ public IApplicationBuilderFactory ApplicationBuilderFactory { get; }
+ public IEnumerable StartupFilters { get; }
+ public IConfiguration Configuration { get; }
+ public IHostingEnvironment HostingEnvironment { get; }
+
+ public async Task StartAsync(CancellationToken cancellationToken)
+ {
+ HostingEventSource.Log.HostStart();
+
+ var serverAddressesFeature = Server.Features?.Get();
+ var addresses = serverAddressesFeature?.Addresses;
+ if (addresses != null && !addresses.IsReadOnly && addresses.Count == 0)
+ {
+ var urls = Configuration[WebHostDefaults.ServerUrlsKey];
+ if (!string.IsNullOrEmpty(urls))
+ {
+ serverAddressesFeature.PreferHostingUrls = WebHostUtilities.ParseBool(Configuration, WebHostDefaults.PreferHostingUrlsKey);
+
+ foreach (var value in urls.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries))
+ {
+ addresses.Add(value);
+ }
+ }
+ }
+
+ RequestDelegate application = null;
+
+ try
+ {
+ Action configure = Options.ConfigureApplication;
+
+ if (configure == null)
+ {
+ throw new InvalidOperationException($"No application configured. Please specify an application via IWebHostBuilder.UseStartup, IWebHostBuilder.Configure, or specifying the startup assembly via {nameof(WebHostDefaults.StartupAssemblyKey)} in the web host configuration.");
+ }
+
+ var builder = ApplicationBuilderFactory.CreateBuilder(Server.Features);
+
+ foreach (var filter in StartupFilters.Reverse())
+ {
+ configure = filter.Configure(configure);
+ }
+
+ configure(builder);
+
+ // Build the request pipeline
+ application = builder.Build();
+ }
+ catch (Exception ex)
+ {
+ Logger.ApplicationError(ex);
+
+ if (!Options.WebHostOptions.CaptureStartupErrors)
+ {
+ throw;
+ }
+
+ application = BuildErrorPageApplication(ex);
+ }
+
+ var httpApplication = new HostingApplication(application, Logger, DiagnosticListener, HttpContextFactory);
+
+ await Server.StartAsync(httpApplication, cancellationToken);
+
+ if (addresses != null)
+ {
+ foreach (var address in addresses)
+ {
+ Logger.LogInformation("Now listening on: {address}", address);
+ }
+ }
+
+ if (Logger.IsEnabled(LogLevel.Debug))
+ {
+ foreach (var assembly in Options.WebHostOptions.GetFinalHostingStartupAssemblies())
+ {
+ Logger.LogDebug("Loaded hosting startup assembly {assemblyName}", assembly);
+ }
+ }
+
+ if (Options.HostingStartupExceptions != null)
+ {
+ foreach (var exception in Options.HostingStartupExceptions.InnerExceptions)
+ {
+ Logger.HostingStartupAssemblyError(exception);
+ }
+ }
+ }
+
+ private RequestDelegate BuildErrorPageApplication(Exception exception)
+ {
+ if (exception is TargetInvocationException tae)
+ {
+ exception = tae.InnerException;
+ }
+
+ var showDetailedErrors = HostingEnvironment.IsDevelopment() || Options.WebHostOptions.DetailedErrors;
+
+ var model = new ErrorPageModel
+ {
+ RuntimeDisplayName = RuntimeInformation.FrameworkDescription
+ };
+ var systemRuntimeAssembly = typeof(System.ComponentModel.DefaultValueAttribute).GetTypeInfo().Assembly;
+ var assemblyVersion = new AssemblyName(systemRuntimeAssembly.FullName).Version.ToString();
+ var clrVersion = assemblyVersion;
+ model.RuntimeArchitecture = RuntimeInformation.ProcessArchitecture.ToString();
+ var currentAssembly = typeof(ErrorPage).GetTypeInfo().Assembly;
+ model.CurrentAssemblyVesion = currentAssembly
+ .GetCustomAttribute()
+ .InformationalVersion;
+ model.ClrVersion = clrVersion;
+ model.OperatingSystemDescription = RuntimeInformation.OSDescription;
+
+ if (showDetailedErrors)
+ {
+ var exceptionDetailProvider = new ExceptionDetailsProvider(
+ HostingEnvironment.ContentRootFileProvider,
+ sourceCodeLineCount: 6);
+
+ model.ErrorDetails = exceptionDetailProvider.GetDetails(exception);
+ }
+ else
+ {
+ model.ErrorDetails = new ExceptionDetails[0];
+ }
+
+ var errorPage = new ErrorPage(model);
+ return context =>
+ {
+ context.Response.StatusCode = 500;
+ context.Response.Headers["Cache-Control"] = "no-cache";
+ return errorPage.ExecuteAsync(context);
+ };
+ }
+
+ public async Task StopAsync(CancellationToken cancellationToken)
+ {
+ try
+ {
+ await Server.StopAsync(cancellationToken);
+ }
+ finally
+ {
+ HostingEventSource.Log.HostStop();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Hosting/Hosting/src/GenericHost/HostingStartupWebHostBuilder.cs b/src/Hosting/Hosting/src/GenericHost/HostingStartupWebHostBuilder.cs
new file mode 100644
index 0000000000..52eaec8179
--- /dev/null
+++ b/src/Hosting/Hosting/src/GenericHost/HostingStartupWebHostBuilder.cs
@@ -0,0 +1,79 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace Microsoft.AspNetCore.Hosting.Internal
+{
+ // We use this type to capture calls to the IWebHostBuilder so the we can properly order calls to
+ // to GenericHostWebHostBuilder.
+ internal class HostingStartupWebHostBuilder : IWebHostBuilder, ISupportsStartup, ISupportsUseDefaultServiceProvider
+ {
+ private readonly GenericWebHostBuilder _builder;
+ private Action _configureConfiguration;
+ private Action _configureServices;
+
+ public HostingStartupWebHostBuilder(GenericWebHostBuilder builder)
+ {
+ _builder = builder;
+ }
+
+ public IWebHost Build()
+ {
+ throw new NotSupportedException($"Building this implementation of {nameof(IWebHostBuilder)} is not supported.");
+ }
+
+ public IWebHostBuilder ConfigureAppConfiguration(Action configureDelegate)
+ {
+ _configureConfiguration += configureDelegate;
+ return this;
+ }
+
+ public IWebHostBuilder ConfigureServices(Action configureServices)
+ {
+ return ConfigureServices((context, services) => configureServices(services));
+ }
+
+ public IWebHostBuilder ConfigureServices(Action configureServices)
+ {
+ _configureServices += configureServices;
+ return this;
+ }
+
+ public string GetSetting(string key) => _builder.GetSetting(key);
+
+ public IWebHostBuilder UseSetting(string key, string value)
+ {
+ _builder.UseSetting(key, value);
+ return this;
+ }
+
+ public void ConfigureServices(WebHostBuilderContext context, IServiceCollection services)
+ {
+ _configureServices?.Invoke(context, services);
+ }
+
+ public void ConfigureAppConfiguration(WebHostBuilderContext context, IConfigurationBuilder builder)
+ {
+ _configureConfiguration?.Invoke(context, builder);
+ }
+
+ public IWebHostBuilder UseDefaultServiceProvider(Action configure)
+ {
+ return _builder.UseDefaultServiceProvider(configure);
+ }
+
+ public IWebHostBuilder Configure(Action configure)
+ {
+ return _builder.Configure(configure);
+ }
+
+ public IWebHostBuilder UseStartup(Type startupType)
+ {
+ return _builder.UseStartup(startupType);
+ }
+ }
+}
diff --git a/src/Hosting/Hosting/src/GenericHost/ISupportsStartup.cs b/src/Hosting/Hosting/src/GenericHost/ISupportsStartup.cs
new file mode 100644
index 0000000000..16322c8bea
--- /dev/null
+++ b/src/Hosting/Hosting/src/GenericHost/ISupportsStartup.cs
@@ -0,0 +1,14 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using Microsoft.AspNetCore.Builder;
+
+namespace Microsoft.AspNetCore.Hosting.Internal
+{
+ internal interface ISupportsStartup
+ {
+ IWebHostBuilder Configure(Action configure);
+ IWebHostBuilder UseStartup(Type startupType);
+ }
+}
diff --git a/src/Hosting/Hosting/src/GenericHost/ISupportsUseDefaultServiceProvider.cs b/src/Hosting/Hosting/src/GenericHost/ISupportsUseDefaultServiceProvider.cs
new file mode 100644
index 0000000000..bf9813cd6e
--- /dev/null
+++ b/src/Hosting/Hosting/src/GenericHost/ISupportsUseDefaultServiceProvider.cs
@@ -0,0 +1,13 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace Microsoft.AspNetCore.Hosting.Internal
+{
+ internal interface ISupportsUseDefaultServiceProvider
+ {
+ IWebHostBuilder UseDefaultServiceProvider(Action configure);
+ }
+}
diff --git a/src/Hosting/Hosting/src/GenericHostWebHostBuilderExtensions.cs b/src/Hosting/Hosting/src/GenericHostWebHostBuilderExtensions.cs
new file mode 100644
index 0000000000..ea903ad7b5
--- /dev/null
+++ b/src/Hosting/Hosting/src/GenericHostWebHostBuilderExtensions.cs
@@ -0,0 +1,16 @@
+using System;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Hosting.Internal;
+
+namespace Microsoft.Extensions.Hosting
+{
+ public static class GenericHostWebHostBuilderExtensions
+ {
+ public static IHostBuilder ConfigureWebHost(this IHostBuilder builder, Action configure)
+ {
+ var webhostBuilder = new GenericWebHostBuilder(builder);
+ configure(webhostBuilder);
+ return builder;
+ }
+ }
+}
diff --git a/src/Hosting/Hosting/src/Internal/ConfigureContainerBuilder.cs b/src/Hosting/Hosting/src/Internal/ConfigureContainerBuilder.cs
index ed8d0fd06e..8791a918ab 100644
--- a/src/Hosting/Hosting/src/Internal/ConfigureContainerBuilder.cs
+++ b/src/Hosting/Hosting/src/Internal/ConfigureContainerBuilder.cs
@@ -15,7 +15,7 @@ namespace Microsoft.AspNetCore.Hosting.Internal
public MethodInfo MethodInfo { get; }
- public Func, Action