diff --git a/src/DefaultBuilder/src/PublicAPI.Unshipped.txt b/src/DefaultBuilder/src/PublicAPI.Unshipped.txt
index 7dc5c58110bf..c4dde0ab6378 100644
--- a/src/DefaultBuilder/src/PublicAPI.Unshipped.txt
+++ b/src/DefaultBuilder/src/PublicAPI.Unshipped.txt
@@ -1 +1,4 @@
#nullable enable
+static Microsoft.AspNetCore.Builder.WebApplication.CreateSlimBuilder() -> Microsoft.AspNetCore.Builder.WebApplicationBuilder!
+static Microsoft.AspNetCore.Builder.WebApplication.CreateSlimBuilder(Microsoft.AspNetCore.Builder.WebApplicationOptions! options) -> Microsoft.AspNetCore.Builder.WebApplicationBuilder!
+static Microsoft.AspNetCore.Builder.WebApplication.CreateSlimBuilder(string![]! args) -> Microsoft.AspNetCore.Builder.WebApplicationBuilder!
diff --git a/src/DefaultBuilder/src/WebApplication.cs b/src/DefaultBuilder/src/WebApplication.cs
index 1a9db8c6df1e..6056b3ff4d02 100644
--- a/src/DefaultBuilder/src/WebApplication.cs
+++ b/src/DefaultBuilder/src/WebApplication.cs
@@ -98,6 +98,13 @@ public static WebApplication Create(string[]? args = null) =>
public static WebApplicationBuilder CreateBuilder() =>
new(new());
+ ///
+ /// Initializes a new instance of the class with minimal defaults.
+ ///
+ /// The .
+ public static WebApplicationBuilder CreateSlimBuilder() =>
+ new(new(), slim: true);
+
///
/// Initializes a new instance of the class with preconfigured defaults.
///
@@ -106,6 +113,14 @@ public static WebApplicationBuilder CreateBuilder() =>
public static WebApplicationBuilder CreateBuilder(string[] args) =>
new(new() { Args = args });
+ ///
+ /// Initializes a new instance of the class with minimal defaults.
+ ///
+ /// Command line arguments
+ /// The .
+ public static WebApplicationBuilder CreateSlimBuilder(string[] args) =>
+ new(new() { Args = args }, slim: true);
+
///
/// Initializes a new instance of the class with preconfigured defaults.
///
@@ -114,6 +129,14 @@ public static WebApplicationBuilder CreateBuilder(string[] args) =>
public static WebApplicationBuilder CreateBuilder(WebApplicationOptions options) =>
new(options);
+ ///
+ /// Initializes a new instance of the class with minimal defaults.
+ ///
+ /// The to configure the .
+ /// The .
+ public static WebApplicationBuilder CreateSlimBuilder(WebApplicationOptions options) =>
+ new(options, slim: true);
+
///
/// Start the application.
///
diff --git a/src/DefaultBuilder/src/WebApplicationBuilder.cs b/src/DefaultBuilder/src/WebApplicationBuilder.cs
index 3da1ac4e83a7..0f7bca59694c 100644
--- a/src/DefaultBuilder/src/WebApplicationBuilder.cs
+++ b/src/DefaultBuilder/src/WebApplicationBuilder.cs
@@ -86,6 +86,97 @@ internal WebApplicationBuilder(WebApplicationOptions options, Action? configureDefaults = null)
+ {
+ Debug.Assert(slim, "should only be called with slim: true");
+
+ var configuration = new ConfigurationManager();
+
+ configuration.AddEnvironmentVariables(prefix: "ASPNETCORE_");
+
+ // add the default host configuration sources, so they are picked up by the HostApplicationBuilder constructor.
+ // These won't be added by HostApplicationBuilder since DisableDefaults = true.
+ configuration.AddEnvironmentVariables(prefix: "DOTNET_");
+ if (options.Args is { Length: > 0 } args)
+ {
+ configuration.AddCommandLine(args);
+ }
+
+ _hostApplicationBuilder = new HostApplicationBuilder(new HostApplicationBuilderSettings
+ {
+ DisableDefaults = true,
+ Args = options.Args,
+ ApplicationName = options.ApplicationName,
+ EnvironmentName = options.EnvironmentName,
+ ContentRootPath = options.ContentRootPath,
+ Configuration = configuration,
+ });
+
+ // configure the ServiceProviderOptions here since DisableDefaults = true means HostApplicationBuilder won't.
+ var serviceProviderFactory = GetServiceProviderFactory(_hostApplicationBuilder);
+ _hostApplicationBuilder.ConfigureContainer(serviceProviderFactory);
+
+ // Set WebRootPath if necessary
+ if (options.WebRootPath is not null)
+ {
+ Configuration.AddInMemoryCollection(new[]
+ {
+ new KeyValuePair(WebHostDefaults.WebRootKey, options.WebRootPath),
+ });
+ }
+
+ // Run methods to configure web host defaults early to populate services
+ var bootstrapHostBuilder = new BootstrapHostBuilder(_hostApplicationBuilder);
+
+ // This is for testing purposes
+ configureDefaults?.Invoke(bootstrapHostBuilder);
+
+ bootstrapHostBuilder.ConfigureSlimWebHost(
+ webHostBuilder =>
+ {
+ AspNetCore.WebHost.UseKestrel(webHostBuilder);
+
+ webHostBuilder.Configure(ConfigureEmptyApplication);
+
+ webHostBuilder.UseSetting(WebHostDefaults.ApplicationKey, _hostApplicationBuilder.Environment.ApplicationName ?? "");
+ webHostBuilder.UseSetting(WebHostDefaults.PreventHostingStartupKey, Configuration[WebHostDefaults.PreventHostingStartupKey]);
+ webHostBuilder.UseSetting(WebHostDefaults.HostingStartupAssembliesKey, Configuration[WebHostDefaults.HostingStartupAssembliesKey]);
+ webHostBuilder.UseSetting(WebHostDefaults.HostingStartupExcludeAssembliesKey, Configuration[WebHostDefaults.HostingStartupExcludeAssembliesKey]);
+ },
+ options =>
+ {
+ // We've already applied "ASPNETCORE_" environment variables to hosting config
+ options.SuppressEnvironmentConfiguration = true;
+ });
+
+ // This applies the config from ConfigureWebHostDefaults
+ // Grab the GenericWebHostService ServiceDescriptor so we can append it after any user-added IHostedServices during Build();
+ _genericWebHostServiceDescriptor = bootstrapHostBuilder.RunDefaultCallbacks();
+
+ // Grab the WebHostBuilderContext from the property bag to use in the ConfigureWebHostBuilder. Then
+ // grab the IWebHostEnvironment from the webHostContext. This also matches the instance in the IServiceCollection.
+ var webHostContext = (WebHostBuilderContext)bootstrapHostBuilder.Properties[typeof(WebHostBuilderContext)];
+ Environment = webHostContext.HostingEnvironment;
+
+ Host = new ConfigureHostBuilder(bootstrapHostBuilder.Context, Configuration, Services);
+ WebHost = new ConfigureWebHostBuilder(webHostContext, Configuration, Services);
+ }
+
+ private static DefaultServiceProviderFactory GetServiceProviderFactory(HostApplicationBuilder hostApplicationBuilder)
+ {
+ if (hostApplicationBuilder.Environment.IsDevelopment())
+ {
+ return new DefaultServiceProviderFactory(
+ new ServiceProviderOptions
+ {
+ ValidateScopes = true,
+ ValidateOnBuild = true,
+ });
+ }
+
+ return new DefaultServiceProviderFactory();
+ }
+
///
/// Provides information about the web hosting environment an application is running.
///
@@ -133,6 +224,46 @@ public WebApplication Build()
}
private void ConfigureApplication(WebHostBuilderContext context, IApplicationBuilder app)
+ {
+ ConfigureApplicationCore(
+ context,
+ app,
+ processAuthMiddlewares: () =>
+ {
+ Debug.Assert(_builtApplication is not null);
+
+ // Process authorization and authentication middlewares independently to avoid
+ // registering middlewares for services that do not exist
+ var serviceProviderIsService = _builtApplication.Services.GetService();
+ if (serviceProviderIsService?.IsService(typeof(IAuthenticationSchemeProvider)) is true)
+ {
+ // Don't add more than one instance of the middleware
+ if (!_builtApplication.Properties.ContainsKey(AuthenticationMiddlewareSetKey))
+ {
+ // The Use invocations will set the property on the outer pipeline,
+ // but we want to set it on the inner pipeline as well.
+ _builtApplication.Properties[AuthenticationMiddlewareSetKey] = true;
+ app.UseAuthentication();
+ }
+ }
+
+ if (serviceProviderIsService?.IsService(typeof(IAuthorizationHandlerProvider)) is true)
+ {
+ if (!_builtApplication.Properties.ContainsKey(AuthorizationMiddlewareSetKey))
+ {
+ _builtApplication.Properties[AuthorizationMiddlewareSetKey] = true;
+ app.UseAuthorization();
+ }
+ }
+ });
+ }
+
+ private void ConfigureEmptyApplication(WebHostBuilderContext context, IApplicationBuilder app)
+ {
+ ConfigureApplicationCore(context, app, processAuthMiddlewares: null);
+ }
+
+ private void ConfigureApplicationCore(WebHostBuilderContext context, IApplicationBuilder app, Action? processAuthMiddlewares)
{
Debug.Assert(_builtApplication is not null);
@@ -173,29 +304,7 @@ private void ConfigureApplication(WebHostBuilderContext context, IApplicationBui
}
}
- // Process authorization and authentication middlewares independently to avoid
- // registering middlewares for services that do not exist
- var serviceProviderIsService = _builtApplication.Services.GetService();
- if (serviceProviderIsService?.IsService(typeof(IAuthenticationSchemeProvider)) is true)
- {
- // Don't add more than one instance of the middleware
- if (!_builtApplication.Properties.ContainsKey(AuthenticationMiddlewareSetKey))
- {
- // The Use invocations will set the property on the outer pipeline,
- // but we want to set it on the inner pipeline as well.
- _builtApplication.Properties[AuthenticationMiddlewareSetKey] = true;
- app.UseAuthentication();
- }
- }
-
- if (serviceProviderIsService?.IsService(typeof(IAuthorizationHandlerProvider)) is true)
- {
- if (!_builtApplication.Properties.ContainsKey(AuthorizationMiddlewareSetKey))
- {
- _builtApplication.Properties[AuthorizationMiddlewareSetKey] = true;
- app.UseAuthorization();
- }
- }
+ processAuthMiddlewares?.Invoke();
// Wire the source pipeline to run in the destination pipeline
app.Use(next =>
diff --git a/src/DefaultBuilder/src/WebHost.cs b/src/DefaultBuilder/src/WebHost.cs
index 156efd0e326e..4a49c3ef8e3c 100644
--- a/src/DefaultBuilder/src/WebHost.cs
+++ b/src/DefaultBuilder/src/WebHost.cs
@@ -222,6 +222,16 @@ internal static void ConfigureWebDefaults(IWebHostBuilder builder)
StaticWebAssetsLoader.UseStaticWebAssets(ctx.HostingEnvironment, ctx.Configuration);
}
});
+
+ UseKestrel(builder);
+
+ builder
+ .UseIIS()
+ .UseIISIntegration();
+ }
+
+ internal static void UseKestrel(IWebHostBuilder builder)
+ {
builder.UseKestrel((builderContext, options) =>
{
options.Configure(builderContext.Configuration.GetSection("Kestrel"), reloadOnChange: true);
@@ -248,9 +258,7 @@ internal static void ConfigureWebDefaults(IWebHostBuilder builder)
services.AddTransient, ForwardedHeadersOptionsSetup>();
services.AddRouting();
- })
- .UseIIS()
- .UseIISIntegration();
+ });
}
///
diff --git a/src/DefaultBuilder/test/Microsoft.AspNetCore.Tests/WebApplicationTests.cs b/src/DefaultBuilder/test/Microsoft.AspNetCore.Tests/WebApplicationTests.cs
index ea386a85e0b2..104e13788f2c 100644
--- a/src/DefaultBuilder/test/Microsoft.AspNetCore.Tests/WebApplicationTests.cs
+++ b/src/DefaultBuilder/test/Microsoft.AspNetCore.Tests/WebApplicationTests.cs
@@ -36,20 +36,77 @@ namespace Microsoft.AspNetCore.Tests;
public class WebApplicationTests
{
- [Fact]
- public async Task WebApplicationBuilder_New()
+ public delegate WebApplicationBuilder CreateBuilderFunc();
+ public delegate WebApplicationBuilder CreateBuilderArgsFunc(string[] args);
+ public delegate WebApplicationBuilder CreateBuilderOptionsFunc(WebApplicationOptions options);
+ public delegate WebApplicationBuilder WebApplicationBuilderConstructorFunc(WebApplicationOptions options, Action configureDefaults);
+
+ private static WebApplicationBuilder CreateBuilder() => WebApplication.CreateBuilder();
+ private static WebApplicationBuilder CreateSlimBuilder() => WebApplication.CreateSlimBuilder();
+
+ public static IEnumerable CreateBuilderFuncs
+ {
+ get
+ {
+ yield return new[] { (CreateBuilderFunc)CreateBuilder };
+ yield return new[] { (CreateBuilderFunc)CreateSlimBuilder };
+ }
+ }
+
+ private static WebApplicationBuilder CreateBuilderArgs(string[] args) => WebApplication.CreateBuilder(args);
+ private static WebApplicationBuilder CreateSlimBuilderArgs(string[] args) => WebApplication.CreateSlimBuilder(args);
+
+ public static IEnumerable CreateBuilderArgsFuncs
+ {
+ get
+ {
+ yield return new[] { (CreateBuilderArgsFunc)CreateBuilderArgs };
+ yield return new[] { (CreateBuilderArgsFunc)CreateSlimBuilderArgs };
+ }
+ }
+
+ private static WebApplicationBuilder CreateBuilderOptions(WebApplicationOptions options) => WebApplication.CreateBuilder(options);
+ private static WebApplicationBuilder CreateSlimBuilderOptions(WebApplicationOptions options) => WebApplication.CreateSlimBuilder(options);
+
+ public static IEnumerable CreateBuilderOptionsFuncs
+ {
+ get
+ {
+ yield return new[] { (CreateBuilderOptionsFunc)CreateBuilderOptions };
+ yield return new[] { (CreateBuilderOptionsFunc)CreateSlimBuilderOptions };
+ }
+ }
+
+ private static WebApplicationBuilder WebApplicationBuilderConstructor(WebApplicationOptions options, Action configureDefaults)
+ => new WebApplicationBuilder(options, configureDefaults);
+ private static WebApplicationBuilder WebApplicationSlimBuilderConstructor(WebApplicationOptions options, Action configureDefaults)
+ => new WebApplicationBuilder(options, slim: true, configureDefaults);
+
+ public static IEnumerable WebApplicationBuilderConstructorFuncs
{
- var builder = WebApplication.CreateBuilder(new string[] { "--urls", "http://localhost:5001" });
+ get
+ {
+ yield return new[] { (WebApplicationBuilderConstructorFunc)WebApplicationBuilderConstructor };
+ yield return new[] { (WebApplicationBuilderConstructorFunc)WebApplicationSlimBuilderConstructor };
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(CreateBuilderArgsFuncs))]
+ public async Task WebApplicationBuilder_New(CreateBuilderArgsFunc createBuilder)
+ {
+ var builder = createBuilder(new string[] { "--urls", "http://localhost:5001" });
await using var app = builder.Build();
var newApp = (app as IApplicationBuilder).New();
Assert.NotNull(newApp.ServerFeatures);
}
- [Fact]
- public async Task WebApplicationBuilderConfiguration_IncludesCommandLineArguments()
+ [Theory]
+ [MemberData(nameof(CreateBuilderArgsFuncs))]
+ public async Task WebApplicationBuilderConfiguration_IncludesCommandLineArguments(CreateBuilderArgsFunc createBuilder)
{
- var builder = WebApplication.CreateBuilder(new string[] { "--urls", "http://localhost:5001" });
+ var builder = createBuilder(new string[] { "--urls", "http://localhost:5001" });
Assert.Equal("http://localhost:5001", builder.Configuration["urls"]);
var urls = new List();
@@ -68,10 +125,11 @@ public async Task WebApplicationBuilderConfiguration_IncludesCommandLineArgument
Assert.Equal("http://localhost:5001", url);
}
- [Fact]
- public async Task WebApplicationRunAsync_UsesDefaultUrls()
+ [Theory]
+ [MemberData(nameof(CreateBuilderFuncs))]
+ public async Task WebApplicationRunAsync_UsesDefaultUrls(CreateBuilderFunc createBuilder)
{
- var builder = WebApplication.CreateBuilder();
+ var builder = createBuilder();
var urls = new List();
var server = new MockAddressesServer(urls);
builder.Services.AddSingleton(server);
@@ -86,10 +144,11 @@ public async Task WebApplicationRunAsync_UsesDefaultUrls()
Assert.Equal("https://localhost:5001", urls[1]);
}
- [Fact]
- public async Task WebApplicationRunUrls_UpdatesIServerAddressesFeature()
+ [Theory]
+ [MemberData(nameof(CreateBuilderFuncs))]
+ public async Task WebApplicationRunUrls_UpdatesIServerAddressesFeature(CreateBuilderFunc createBuilder)
{
- var builder = WebApplication.CreateBuilder();
+ var builder = createBuilder();
var urls = new List();
var server = new MockAddressesServer(urls);
builder.Services.AddSingleton(server);
@@ -104,10 +163,11 @@ public async Task WebApplicationRunUrls_UpdatesIServerAddressesFeature()
await runTask;
}
- [Fact]
- public async Task WebApplicationUrls_UpdatesIServerAddressesFeature()
+ [Theory]
+ [MemberData(nameof(CreateBuilderFuncs))]
+ public async Task WebApplicationUrls_UpdatesIServerAddressesFeature(CreateBuilderFunc createBuilder)
{
- var builder = WebApplication.CreateBuilder();
+ var builder = createBuilder();
var urls = new List();
var server = new MockAddressesServer(urls);
builder.Services.AddSingleton(server);
@@ -123,10 +183,11 @@ public async Task WebApplicationUrls_UpdatesIServerAddressesFeature()
Assert.Equal("https://localhost:5003", urls[1]);
}
- [Fact]
- public async Task WebApplicationRunUrls_OverridesIServerAddressesFeature()
+ [Theory]
+ [MemberData(nameof(CreateBuilderFuncs))]
+ public async Task WebApplicationRunUrls_OverridesIServerAddressesFeature(CreateBuilderFunc createBuilder)
{
- var builder = WebApplication.CreateBuilder();
+ var builder = createBuilder();
var urls = new List();
var server = new MockAddressesServer(urls);
builder.Services.AddSingleton(server);
@@ -144,20 +205,22 @@ public async Task WebApplicationRunUrls_OverridesIServerAddressesFeature()
await runTask;
}
- [Fact]
- public async Task WebApplicationUrls_ThrowsInvalidOperationExceptionIfThereIsNoIServerAddressesFeature()
+ [Theory]
+ [MemberData(nameof(CreateBuilderFuncs))]
+ public async Task WebApplicationUrls_ThrowsInvalidOperationExceptionIfThereIsNoIServerAddressesFeature(CreateBuilderFunc createBuilder)
{
- var builder = WebApplication.CreateBuilder();
+ var builder = createBuilder();
builder.Services.AddSingleton(new MockAddressesServer());
await using var app = builder.Build();
Assert.Throws(() => app.Urls);
}
- [Fact]
- public async Task HostedServicesRunBeforeTheServerStarts()
+ [Theory]
+ [MemberData(nameof(CreateBuilderFuncs))]
+ public async Task HostedServicesRunBeforeTheServerStarts(CreateBuilderFunc createBuilder)
{
- var builder = WebApplication.CreateBuilder();
+ var builder = createBuilder();
var startOrder = new List();
var server = new MockServer(startOrder);
var hostedService = new HostedService(startOrder);
@@ -215,42 +278,47 @@ public Task StopAsync(CancellationToken cancellationToken)
}
}
- [Fact]
- public async Task WebApplicationRunUrls_ThrowsInvalidOperationExceptionIfThereIsNoIServerAddressesFeature()
+ [Theory]
+ [MemberData(nameof(CreateBuilderFuncs))]
+ public async Task WebApplicationRunUrls_ThrowsInvalidOperationExceptionIfThereIsNoIServerAddressesFeature(CreateBuilderFunc createBuilder)
{
- var builder = WebApplication.CreateBuilder();
+ var builder = createBuilder();
builder.Services.AddSingleton(new MockAddressesServer());
await using var app = builder.Build();
await Assert.ThrowsAsync(() => app.RunAsync("http://localhost:5001"));
}
- [Fact]
- public async Task WebApplicationRunUrls_ThrowsInvalidOperationExceptionIfServerAddressesFeatureIsReadOnly()
+ [Theory]
+ [MemberData(nameof(CreateBuilderFuncs))]
+ public async Task WebApplicationRunUrls_ThrowsInvalidOperationExceptionIfServerAddressesFeatureIsReadOnly(CreateBuilderFunc createBuilder)
{
- var builder = WebApplication.CreateBuilder();
+ var builder = createBuilder();
builder.Services.AddSingleton(new MockAddressesServer(new List().AsReadOnly()));
await using var app = builder.Build();
await Assert.ThrowsAsync(() => app.RunAsync("http://localhost:5001"));
}
- [Fact]
- public void WebApplicationBuilderHost_ThrowsWhenBuiltDirectly()
+ [Theory]
+ [MemberData(nameof(CreateBuilderFuncs))]
+ public void WebApplicationBuilderHost_ThrowsWhenBuiltDirectly(CreateBuilderFunc createBuilder)
{
- Assert.Throws(() => ((IHostBuilder)WebApplication.CreateBuilder().Host).Build());
+ Assert.Throws(() => ((IHostBuilder)createBuilder().Host).Build());
}
- [Fact]
- public void WebApplicationBuilderWebHost_ThrowsWhenBuiltDirectly()
+ [Theory]
+ [MemberData(nameof(CreateBuilderFuncs))]
+ public void WebApplicationBuilderWebHost_ThrowsWhenBuiltDirectly(CreateBuilderFunc createBuilder)
{
- Assert.Throws(() => ((IWebHostBuilder)WebApplication.CreateBuilder().WebHost).Build());
+ Assert.Throws(() => ((IWebHostBuilder)createBuilder().WebHost).Build());
}
- [Fact]
- public void WebApplicationBuilderWebHostSettingsThatAffectTheHostCannotBeModified()
+ [Theory]
+ [MemberData(nameof(CreateBuilderFuncs))]
+ public void WebApplicationBuilderWebHostSettingsThatAffectTheHostCannotBeModified(CreateBuilderFunc createBuilder)
{
- var builder = WebApplication.CreateBuilder();
+ var builder = createBuilder();
var contentRoot = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
var webRoot = Path.Combine(contentRoot, "wwwroot");
@@ -266,10 +334,11 @@ public void WebApplicationBuilderWebHostSettingsThatAffectTheHostCannotBeModifie
Assert.Throws(() => builder.WebHost.UseContentRoot(contentRoot));
}
- [Fact]
- public void WebApplicationBuilderWebHostSettingsThatAffectTheHostCannotBeModifiedViaConfigureAppConfiguration()
+ [Theory]
+ [MemberData(nameof(CreateBuilderFuncs))]
+ public void WebApplicationBuilderWebHostSettingsThatAffectTheHostCannotBeModifiedViaConfigureAppConfiguration(CreateBuilderFunc createBuilder)
{
- var builder = WebApplication.CreateBuilder();
+ var builder = createBuilder();
var contentRoot = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
var webRoot = Path.Combine(contentRoot, "wwwroot");
@@ -324,13 +393,14 @@ public void WebApplicationBuilderWebHostSettingsThatAffectTheHostCannotBeModifie
}));
}
- [Fact]
- public void SettingContentRootToSameCanonicalValueWorks()
+ [Theory]
+ [MemberData(nameof(CreateBuilderOptionsFuncs))]
+ public void SettingContentRootToSameCanonicalValueWorks(CreateBuilderOptionsFunc createBuilder)
{
var contentRoot = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(contentRoot);
- var builder = WebApplication.CreateBuilder(new WebApplicationOptions
+ var builder = createBuilder(new WebApplicationOptions
{
ContentRootPath = contentRoot
});
@@ -344,13 +414,21 @@ public void SettingContentRootToSameCanonicalValueWorks()
builder.WebHost.UseContentRoot(contentRoot.ToLowerInvariant());
}
+ public static IEnumerable CanHandleVariousWebRootPathsData
+ {
+ get
+ {
+ foreach (string webRoot in new[] { "wwwroot2", "./wwwroot2", "./bar/../wwwroot2", "foo/../wwwroot2", "wwwroot2/." })
+ {
+ yield return new object[] { webRoot, (CreateBuilderOptionsFunc)CreateBuilderOptions };
+ yield return new object[] { webRoot, (CreateBuilderOptionsFunc)CreateSlimBuilderOptions };
+ }
+ }
+ }
+
[Theory]
- [InlineData("wwwroot2")]
- [InlineData("./wwwroot2")]
- [InlineData("./bar/../wwwroot2")]
- [InlineData("foo/../wwwroot2")]
- [InlineData("wwwroot2/.")]
- public void WebApplicationBuilder_CanHandleVariousWebRootPaths(string webRoot)
+ [MemberData(nameof(CanHandleVariousWebRootPathsData))]
+ public void WebApplicationBuilder_CanHandleVariousWebRootPaths(string webRoot, CreateBuilderOptionsFunc createBuilder)
{
var contentRoot = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
Directory.CreateDirectory(contentRoot);
@@ -364,7 +442,7 @@ public void WebApplicationBuilder_CanHandleVariousWebRootPaths(string webRoot)
WebRootPath = "wwwroot2"
};
- var builder = new WebApplicationBuilder(options);
+ var builder = createBuilder(options);
Assert.Equal(contentRoot, builder.Environment.ContentRootPath);
Assert.Equal(fullWebRootPath, builder.Environment.WebRootPath);
@@ -377,8 +455,9 @@ public void WebApplicationBuilder_CanHandleVariousWebRootPaths(string webRoot)
}
}
- [Fact]
- public void WebApplicationBuilder_CanOverrideWithFullWebRootPaths()
+ [Theory]
+ [MemberData(nameof(CreateBuilderOptionsFuncs))]
+ public void WebApplicationBuilder_CanOverrideWithFullWebRootPaths(CreateBuilderOptionsFunc createBuilder)
{
var contentRoot = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
Directory.CreateDirectory(contentRoot);
@@ -392,7 +471,7 @@ public void WebApplicationBuilder_CanOverrideWithFullWebRootPaths()
ContentRootPath = contentRoot,
};
- var builder = new WebApplicationBuilder(options);
+ var builder = createBuilder(options);
Assert.Equal(contentRoot, builder.Environment.ContentRootPath);
Assert.Equal(fullWebRootPath, builder.Environment.WebRootPath);
@@ -405,13 +484,21 @@ public void WebApplicationBuilder_CanOverrideWithFullWebRootPaths()
}
}
+ public static IEnumerable CanHandleVariousWebRootPaths_OverrideDefaultPathData
+ {
+ get
+ {
+ foreach (string webRoot in new[] { "wwwroot", "./wwwroot", "./bar/../wwwroot", "foo/../wwwroot", "wwwroot/." })
+ {
+ yield return new object[] { webRoot, (CreateBuilderOptionsFunc)CreateBuilderOptions };
+ yield return new object[] { webRoot, (CreateBuilderOptionsFunc)CreateSlimBuilderOptions };
+ }
+ }
+ }
+
[Theory]
- [InlineData("wwwroot")]
- [InlineData("./wwwroot")]
- [InlineData("./bar/../wwwroot")]
- [InlineData("foo/../wwwroot")]
- [InlineData("wwwroot/.")]
- public void WebApplicationBuilder_CanHandleVariousWebRootPaths_OverrideDefaultPath(string webRoot)
+ [MemberData(nameof(CanHandleVariousWebRootPaths_OverrideDefaultPathData))]
+ public void WebApplicationBuilder_CanHandleVariousWebRootPaths_OverrideDefaultPath(string webRoot, CreateBuilderOptionsFunc createBuilder)
{
var contentRoot = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
Directory.CreateDirectory(contentRoot);
@@ -425,7 +512,7 @@ public void WebApplicationBuilder_CanHandleVariousWebRootPaths_OverrideDefaultPa
ContentRootPath = contentRoot
};
- var builder = new WebApplicationBuilder(options);
+ var builder = createBuilder(options);
Assert.Equal(contentRoot, builder.Environment.ContentRootPath);
Assert.Equal(fullWebRootPath, builder.Environment.WebRootPath);
@@ -438,12 +525,24 @@ public void WebApplicationBuilder_CanHandleVariousWebRootPaths_OverrideDefaultPa
}
}
+ public static IEnumerable SettingContentRootToRelativePathData
+ {
+ get
+ {
+ // Empty behaves differently to null
+ foreach (string path in new[] { "", "." })
+ {
+ yield return new object[] { path, (CreateBuilderOptionsFunc)CreateBuilderOptions };
+ yield return new object[] { path, (CreateBuilderOptionsFunc)CreateSlimBuilderOptions };
+ }
+ }
+ }
+
[Theory]
- [InlineData("")] // Empty behaves differently to null
- [InlineData(".")]
- public void SettingContentRootToRelativePathUsesAppContextBaseDirectoryAsPathBase(string path)
+ [MemberData(nameof(SettingContentRootToRelativePathData))]
+ public void SettingContentRootToRelativePathUsesAppContextBaseDirectoryAsPathBase(string path, CreateBuilderOptionsFunc createBuilder)
{
- var builder = WebApplication.CreateBuilder(new WebApplicationOptions
+ var builder = createBuilder(new WebApplicationOptions
{
ContentRootPath = path
});
@@ -462,8 +561,9 @@ static string NormalizePath(string unnormalizedPath) =>
Path.TrimEndingDirectorySeparator(Path.GetFullPath(unnormalizedPath));
}
- [Fact]
- public void WebApplicationBuilderSettingInvalidApplicationDoesNotThrowWhenAssemblyLoadForUserSecretsFail()
+ [Theory]
+ [MemberData(nameof(CreateBuilderOptionsFuncs))]
+ public void WebApplicationBuilderSettingInvalidApplicationDoesNotThrowWhenAssemblyLoadForUserSecretsFail(CreateBuilderOptionsFunc createBuilder)
{
var options = new WebApplicationOptions
{
@@ -472,14 +572,15 @@ public void WebApplicationBuilderSettingInvalidApplicationDoesNotThrowWhenAssemb
};
// Use secrets fails to load an invalid assembly name but does not throw
- var webApplication = WebApplication.CreateBuilder(options).Build();
+ var webApplication = createBuilder(options).Build();
Assert.Equal(nameof(WebApplicationTests), webApplication.Environment.ApplicationName);
Assert.Equal(Environments.Development, webApplication.Environment.EnvironmentName);
}
- [Fact]
- public void WebApplicationBuilderCanConfigureHostSettingsUsingWebApplicationOptions()
+ [Theory]
+ [MemberData(nameof(WebApplicationBuilderConstructorFuncs))]
+ public void WebApplicationBuilderCanConfigureHostSettingsUsingWebApplicationOptions(WebApplicationBuilderConstructorFunc createBuilder)
{
var contentRoot = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
Directory.CreateDirectory(contentRoot);
@@ -497,7 +598,7 @@ public void WebApplicationBuilderCanConfigureHostSettingsUsingWebApplicationOpti
WebRootPath = webRoot
};
- var builder = new WebApplicationBuilder(
+ var builder = createBuilder(
options,
bootstrapBuilder =>
{
@@ -520,8 +621,9 @@ public void WebApplicationBuilderCanConfigureHostSettingsUsingWebApplicationOpti
}
}
- [Fact]
- public void WebApplicationBuilderWebApplicationOptionsPropertiesOverridesArgs()
+ [Theory]
+ [MemberData(nameof(WebApplicationBuilderConstructorFuncs))]
+ public void WebApplicationBuilderWebApplicationOptionsPropertiesOverridesArgs(WebApplicationBuilderConstructorFunc createBuilder)
{
var contentRoot = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
Directory.CreateDirectory(contentRoot);
@@ -545,7 +647,7 @@ public void WebApplicationBuilderWebApplicationOptionsPropertiesOverridesArgs()
WebRootPath = webRoot
};
- var builder = new WebApplicationBuilder(
+ var builder = createBuilder(
options,
bootstrapBuilder =>
{
@@ -568,8 +670,9 @@ public void WebApplicationBuilderWebApplicationOptionsPropertiesOverridesArgs()
}
}
- [Fact]
- public void WebApplicationBuilderCanConfigureHostSettingsUsingWebApplicationOptionsArgs()
+ [Theory]
+ [MemberData(nameof(WebApplicationBuilderConstructorFuncs))]
+ public void WebApplicationBuilderCanConfigureHostSettingsUsingWebApplicationOptionsArgs(WebApplicationBuilderConstructorFunc createBuilder)
{
var contentRoot = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
Directory.CreateDirectory(contentRoot);
@@ -590,7 +693,7 @@ public void WebApplicationBuilderCanConfigureHostSettingsUsingWebApplicationOpti
}
};
- var builder = new WebApplicationBuilder(
+ var builder = createBuilder(
options,
bootstrapBuilder =>
{
@@ -613,12 +716,13 @@ public void WebApplicationBuilderCanConfigureHostSettingsUsingWebApplicationOpti
}
}
- [Fact]
- public void WebApplicationBuilderApplicationNameDefaultsToEntryAssembly()
+ [Theory]
+ [MemberData(nameof(WebApplicationBuilderConstructorFuncs))]
+ public void WebApplicationBuilderApplicationNameDefaultsToEntryAssembly(WebApplicationBuilderConstructorFunc createBuilder)
{
var assemblyName = Assembly.GetEntryAssembly().GetName().Name;
- var builder = new WebApplicationBuilder(
+ var builder = createBuilder(
new(),
bootstrapBuilder =>
{
@@ -649,8 +753,9 @@ public void WebApplicationBuilderApplicationNameDefaultsToEntryAssembly()
Assert.Equal(assemblyName, webHostEnv.ApplicationName);
}
- [Fact]
- public void WebApplicationBuilderApplicationNameCanBeOverridden()
+ [Theory]
+ [MemberData(nameof(WebApplicationBuilderConstructorFuncs))]
+ public void WebApplicationBuilderApplicationNameCanBeOverridden(WebApplicationBuilderConstructorFunc createBuilder)
{
var assemblyName = typeof(WebApplicationTests).Assembly.GetName().Name;
@@ -659,7 +764,7 @@ public void WebApplicationBuilderApplicationNameCanBeOverridden()
ApplicationName = assemblyName
};
- var builder = new WebApplicationBuilder(
+ var builder = createBuilder(
options,
bootstrapBuilder =>
{
@@ -690,10 +795,11 @@ public void WebApplicationBuilderApplicationNameCanBeOverridden()
Assert.Equal(assemblyName, webHostEnv.ApplicationName);
}
- [Fact]
- public void WebApplicationBuilderCanFlowCommandLineConfigurationToApplication()
+ [Theory]
+ [MemberData(nameof(CreateBuilderArgsFuncs))]
+ public void WebApplicationBuilderCanFlowCommandLineConfigurationToApplication(CreateBuilderArgsFunc createBuilder)
{
- var builder = WebApplication.CreateBuilder(new[] { "--x=1", "--name=Larry", "--age=20", "--environment=Testing" });
+ var builder = createBuilder(new[] { "--x=1", "--name=Larry", "--age=20", "--environment=Testing" });
Assert.Equal("1", builder.Configuration["x"]);
Assert.Equal("Larry", builder.Configuration["name"]);
@@ -723,10 +829,11 @@ public void WebApplicationBuilderCanFlowCommandLineConfigurationToApplication()
Assert.Equal("Testing", app.Configuration["environment"]);
}
- [Fact]
- public void WebApplicationBuilderHostBuilderSettingsThatAffectTheHostCannotBeModified()
+ [Theory]
+ [MemberData(nameof(CreateBuilderFuncs))]
+ public void WebApplicationBuilderHostBuilderSettingsThatAffectTheHostCannotBeModified(CreateBuilderFunc createBuilder)
{
- var builder = WebApplication.CreateBuilder();
+ var builder = createBuilder();
var contentRoot = Path.GetTempPath().ToString();
var envName = $"{nameof(WebApplicationTests)}_ENV";
@@ -743,10 +850,11 @@ public void WebApplicationBuilderHostBuilderSettingsThatAffectTheHostCannotBeMod
Assert.Throws(() => builder.Host.UseContentRoot(contentRoot));
}
- [Fact]
- public void WebApplicationBuilderWebHostUseSettingCanBeReadByConfiguration()
+ [Theory]
+ [MemberData(nameof(CreateBuilderFuncs))]
+ public void WebApplicationBuilderWebHostUseSettingCanBeReadByConfiguration(CreateBuilderFunc createBuilder)
{
- var builder = WebApplication.CreateBuilder();
+ var builder = createBuilder();
builder.WebHost.UseSetting("A", "value");
builder.WebHost.UseSetting("B", "another");
@@ -763,8 +871,9 @@ public void WebApplicationBuilderWebHostUseSettingCanBeReadByConfiguration()
Assert.Equal("another", builder.Configuration["B"]);
}
- [Fact]
- public async Task WebApplicationCanObserveConfigurationChangesMadeInBuild()
+ [Theory]
+ [MemberData(nameof(CreateBuilderFuncs))]
+ public async Task WebApplicationCanObserveConfigurationChangesMadeInBuild(CreateBuilderFunc createBuilder)
{
// This mimics what WebApplicationFactory does and runs configure
// services callbacks
@@ -802,7 +911,7 @@ public async Task WebApplicationCanObserveConfigurationChangesMadeInBuild()
});
});
- var builder = WebApplication.CreateBuilder();
+ var builder = createBuilder();
await using var app = builder.Build();
@@ -821,8 +930,9 @@ public async Task WebApplicationCanObserveConfigurationChangesMadeInBuild()
Assert.Equal("F", builder.Configuration["F"]);
}
- [Fact]
- public async Task WebApplicationCanObserveSourcesClearedInBuild()
+ [Theory]
+ [MemberData(nameof(CreateBuilderFuncs))]
+ public async Task WebApplicationCanObserveSourcesClearedInBuild(CreateBuilderFunc createBuilder)
{
// This mimics what WebApplicationFactory does and runs configure
// services callbacks
@@ -847,7 +957,7 @@ public async Task WebApplicationCanObserveSourcesClearedInBuild()
});
});
- var builder = WebApplication.CreateBuilder();
+ var builder = createBuilder();
builder.Configuration.AddInMemoryCollection(new Dictionary()
{
@@ -864,8 +974,9 @@ public async Task WebApplicationCanObserveSourcesClearedInBuild()
Assert.Same(builder.Configuration, app.Configuration);
}
- [Fact]
- public async Task WebApplicationCanObserveSourcesClearedInConfiguratHostConfiguration()
+ [Theory]
+ [MemberData(nameof(CreateBuilderOptionsFuncs))]
+ public async Task WebApplicationCanObserveSourcesClearedInConfiguratHostConfiguration(CreateBuilderOptionsFunc createBuilder)
{
// This mimics what WebApplicationFactory does and runs configure
// services callbacks
@@ -885,7 +996,7 @@ public async Task WebApplicationCanObserveSourcesClearedInConfiguratHostConfigur
});
});
- var builder = WebApplication.CreateBuilder(new WebApplicationOptions
+ var builder = createBuilder(new WebApplicationOptions
{
ApplicationName = "appName",
EnvironmentName = "environmentName",
@@ -906,8 +1017,9 @@ public async Task WebApplicationCanObserveSourcesClearedInConfiguratHostConfigur
Assert.Same(builder.Configuration, app.Configuration);
}
- [Fact]
- public async Task WebApplicationCanHandleStreamBackedConfigurationAddedInBuild()
+ [Theory]
+ [MemberData(nameof(CreateBuilderFuncs))]
+ public async Task WebApplicationCanHandleStreamBackedConfigurationAddedInBuild(CreateBuilderFunc createBuilder)
{
static Stream CreateStreamFromString(string data) => new MemoryStream(Encoding.UTF8.GetBytes(data));
@@ -922,7 +1034,7 @@ public async Task WebApplicationCanHandleStreamBackedConfigurationAddedInBuild()
hostBuilder.ConfigureAppConfiguration(config => config.AddJsonStream(jsonBStream));
});
- var builder = WebApplication.CreateBuilder();
+ var builder = createBuilder();
await using var app = builder.Build();
Assert.Equal("A", app.Configuration["A"]);
@@ -931,8 +1043,9 @@ public async Task WebApplicationCanHandleStreamBackedConfigurationAddedInBuild()
Assert.Same(builder.Configuration, app.Configuration);
}
- [Fact]
- public async Task WebApplicationDisposesConfigurationProvidersAddedInBuild()
+ [Theory]
+ [MemberData(nameof(CreateBuilderFuncs))]
+ public async Task WebApplicationDisposesConfigurationProvidersAddedInBuild(CreateBuilderFunc createBuilder)
{
var hostConfigSource = new RandomConfigurationSource();
var appConfigSource = new RandomConfigurationSource();
@@ -945,7 +1058,7 @@ public async Task WebApplicationDisposesConfigurationProvidersAddedInBuild()
hostBuilder.ConfigureAppConfiguration(config => config.Add(appConfigSource));
});
- var builder = WebApplication.CreateBuilder();
+ var builder = createBuilder();
{
await using var app = builder.Build();
@@ -966,8 +1079,9 @@ public async Task WebApplicationDisposesConfigurationProvidersAddedInBuild()
Assert.Equal(1, appConfigSource.ProvidersDisposed);
}
- [Fact]
- public async Task WebApplicationMakesOriginalConfigurationProvidersAddedInBuildAccessable()
+ [Theory]
+ [MemberData(nameof(CreateBuilderFuncs))]
+ public async Task WebApplicationMakesOriginalConfigurationProvidersAddedInBuildAccessable(CreateBuilderFunc createBuilder)
{
// This mimics what WebApplicationFactory does and runs configure
// services callbacks
@@ -976,16 +1090,17 @@ public async Task WebApplicationMakesOriginalConfigurationProvidersAddedInBuildA
hostBuilder.ConfigureAppConfiguration(config => config.Add(new RandomConfigurationSource()));
});
- var builder = WebApplication.CreateBuilder();
+ var builder = createBuilder();
await using var app = builder.Build();
Assert.Single(((IConfigurationRoot)app.Configuration).Providers.OfType());
}
- [Fact]
- public void WebApplicationBuilderHostProperties_IsCaseSensitive()
+ [Theory]
+ [MemberData(nameof(CreateBuilderFuncs))]
+ public void WebApplicationBuilderHostProperties_IsCaseSensitive(CreateBuilderFunc createBuilder)
{
- var builder = WebApplication.CreateBuilder();
+ var builder = createBuilder();
builder.Host.Properties["lowercase"] = nameof(WebApplicationTests);
@@ -993,10 +1108,11 @@ public void WebApplicationBuilderHostProperties_IsCaseSensitive()
Assert.False(builder.Host.Properties.ContainsKey("Lowercase"));
}
- [Fact]
- public async Task WebApplicationConfiguration_HostFilterOptionsAreReloadable()
+ [Theory]
+ [MemberData(nameof(CreateBuilderFuncs))]
+ public async Task WebApplicationConfiguration_HostFilterOptionsAreReloadable(CreateBuilderFunc createBuilder)
{
- var builder = WebApplication.CreateBuilder();
+ var builder = createBuilder();
var host = builder.WebHost
.ConfigureAppConfiguration(configBuilder =>
{
@@ -1023,10 +1139,11 @@ public async Task WebApplicationConfiguration_HostFilterOptionsAreReloadable()
Assert.Contains("NewHost", options.AllowedHosts);
}
- [Fact]
- public void CanResolveIConfigurationBeforeBuildingApplication()
+ [Theory]
+ [MemberData(nameof(CreateBuilderFuncs))]
+ public void CanResolveIConfigurationBeforeBuildingApplication(CreateBuilderFunc createBuilder)
{
- var builder = WebApplication.CreateBuilder();
+ var builder = createBuilder();
var sp = builder.Services.BuildServiceProvider();
var config = sp.GetService();
@@ -1038,10 +1155,11 @@ public void CanResolveIConfigurationBeforeBuildingApplication()
Assert.Same(app.Configuration, builder.Configuration);
}
- [Fact]
- public void ManuallyAddingConfigurationAsServiceWorks()
+ [Theory]
+ [MemberData(nameof(CreateBuilderFuncs))]
+ public void ManuallyAddingConfigurationAsServiceWorks(CreateBuilderFunc createBuilder)
{
- var builder = WebApplication.CreateBuilder();
+ var builder = createBuilder();
builder.Services.AddSingleton(builder.Configuration);
var sp = builder.Services.BuildServiceProvider();
@@ -1054,10 +1172,11 @@ public void ManuallyAddingConfigurationAsServiceWorks()
Assert.Same(app.Configuration, builder.Configuration);
}
- [Fact]
- public void AddingMemoryStreamBackedConfigurationWorks()
+ [Theory]
+ [MemberData(nameof(CreateBuilderFuncs))]
+ public void AddingMemoryStreamBackedConfigurationWorks(CreateBuilderFunc createBuilder)
{
- var builder = WebApplication.CreateBuilder();
+ var builder = createBuilder();
var jsonConfig = @"{ ""foo"": ""bar"" }";
using var ms = new MemoryStream();
@@ -1075,10 +1194,11 @@ public void AddingMemoryStreamBackedConfigurationWorks()
Assert.Equal("bar", app.Configuration["foo"]);
}
- [Fact]
- public async Task WebApplicationConfiguration_EnablesForwardedHeadersFromConfig()
+ [Theory]
+ [MemberData(nameof(CreateBuilderFuncs))]
+ public async Task WebApplicationConfiguration_EnablesForwardedHeadersFromConfig(CreateBuilderFunc createBuilder)
{
- var builder = WebApplication.CreateBuilder();
+ var builder = createBuilder();
builder.WebHost.UseTestServer();
builder.Configuration["FORWARDEDHEADERS_ENABLED"] = "true";
await using var app = builder.Build();
@@ -1105,10 +1225,11 @@ public void WebApplicationCreate_RegistersRouting()
Assert.NotNull(linkGenerator);
}
- [Fact]
- public void WebApplication_CanResolveDefaultServicesFromServiceCollection()
+ [Theory]
+ [MemberData(nameof(CreateBuilderFuncs))]
+ public void WebApplication_CanResolveDefaultServicesFromServiceCollection(CreateBuilderFunc createBuilder)
{
- var builder = WebApplication.CreateBuilder();
+ var builder = createBuilder();
// Add the service collection to the service collection
builder.Services.AddSingleton(builder.Services);
@@ -1124,8 +1245,9 @@ public void WebApplication_CanResolveDefaultServicesFromServiceCollection()
Assert.Equal(env0.ContentRootPath, env1.ContentRootPath);
}
- [Fact]
- public async Task WebApplication_CanResolveServicesAddedAfterBuildFromServiceCollection()
+ [Theory]
+ [MemberData(nameof(CreateBuilderFuncs))]
+ public async Task WebApplication_CanResolveServicesAddedAfterBuildFromServiceCollection(CreateBuilderFunc createBuilder)
{
// This mimics what WebApplicationFactory does and runs configure
// services callbacks
@@ -1137,7 +1259,7 @@ public async Task WebApplication_CanResolveServicesAddedAfterBuildFromServiceCol
});
});
- var builder = WebApplication.CreateBuilder();
+ var builder = createBuilder();
// Add the service collection to the service collection
builder.Services.AddSingleton(builder.Services);
@@ -1152,10 +1274,11 @@ public async Task WebApplication_CanResolveServicesAddedAfterBuildFromServiceCol
Assert.IsType(service1);
}
- [Fact]
- public async Task WebApplication_CanResolveIConfigurationFromServiceCollection()
+ [Theory]
+ [MemberData(nameof(CreateBuilderFuncs))]
+ public async Task WebApplication_CanResolveIConfigurationFromServiceCollection(CreateBuilderFunc createBuilder)
{
- var builder = WebApplication.CreateBuilder();
+ var builder = createBuilder();
builder.Configuration.AddInMemoryCollection(new Dictionary
{
@@ -1178,10 +1301,11 @@ public async Task WebApplication_CanResolveIConfigurationFromServiceCollection()
Assert.Equal("bar", app.Configuration["foo"]);
}
- [Fact]
- public void WebApplication_CanResolveDefaultServicesFromServiceCollectionInCorrectOrder()
+ [Theory]
+ [MemberData(nameof(CreateBuilderFuncs))]
+ public void WebApplication_CanResolveDefaultServicesFromServiceCollectionInCorrectOrder(CreateBuilderFunc createBuilder)
{
- var builder = WebApplication.CreateBuilder();
+ var builder = createBuilder();
// Add the service collection to the service collection
builder.Services.AddSingleton(builder.Services);
@@ -1205,10 +1329,11 @@ public void WebApplication_CanResolveDefaultServicesFromServiceCollectionInCorre
Assert.Equal(hostLifetimes1.Length, hostLifetimes0.Length);
}
- [Fact]
- public async Task WebApplication_CanCallUseRoutingWithoutUseEndpoints()
+ [Theory]
+ [MemberData(nameof(CreateBuilderFuncs))]
+ public async Task WebApplication_CanCallUseRoutingWithoutUseEndpoints(CreateBuilderFunc createBuilder)
{
- var builder = WebApplication.CreateBuilder();
+ var builder = createBuilder();
builder.WebHost.UseTestServer();
await using var app = builder.Build();
@@ -1243,10 +1368,11 @@ public async Task WebApplication_CanCallUseRoutingWithoutUseEndpoints()
Assert.Equal("new", await oldResult.Content.ReadAsStringAsync());
}
- [Fact]
- public async Task WebApplication_CanCallUseEndpointsWithoutUseRoutingFails()
+ [Theory]
+ [MemberData(nameof(CreateBuilderFuncs))]
+ public async Task WebApplication_CanCallUseEndpointsWithoutUseRoutingFails(CreateBuilderFunc createBuilder)
{
- var builder = WebApplication.CreateBuilder();
+ var builder = createBuilder();
builder.WebHost.UseTestServer();
await using var app = builder.Build();
@@ -1272,11 +1398,12 @@ public void WebApplicationCreate_RegistersEventSourceLogger()
args.Payload.OfType().Any(p => p.Contains(guid)));
}
- [Fact]
- public void WebApplicationBuilder_CanClearDefaultLoggers()
+ [Theory]
+ [MemberData(nameof(CreateBuilderFuncs))]
+ public void WebApplicationBuilder_CanClearDefaultLoggers(CreateBuilderFunc createBuilder)
{
var listener = new TestEventListener();
- var builder = WebApplication.CreateBuilder();
+ var builder = createBuilder();
builder.Logging.ClearProviders();
var app = builder.Build();
@@ -1291,10 +1418,11 @@ public void WebApplicationBuilder_CanClearDefaultLoggers()
args.Payload.OfType().Any(p => p.Contains(guid)));
}
- [Fact]
- public async Task WebApplicationBuilder_StartupFilterCanAddTerminalMiddleware()
+ [Theory]
+ [MemberData(nameof(CreateBuilderFuncs))]
+ public async Task WebApplicationBuilder_StartupFilterCanAddTerminalMiddleware(CreateBuilderFunc createBuilder)
{
- var builder = WebApplication.CreateBuilder();
+ var builder = createBuilder();
builder.WebHost.UseTestServer();
builder.Services.AddSingleton();
await using var app = builder.Build();
@@ -1312,10 +1440,11 @@ public async Task WebApplicationBuilder_StartupFilterCanAddTerminalMiddleware()
Assert.Equal(418, (int)terminalResult.StatusCode);
}
- [Fact]
- public async Task StartupFilter_WithUseRoutingWorks()
+ [Theory]
+ [MemberData(nameof(CreateBuilderFuncs))]
+ public async Task StartupFilter_WithUseRoutingWorks(CreateBuilderFunc createBuilder)
{
- var builder = WebApplication.CreateBuilder();
+ var builder = createBuilder();
builder.WebHost.UseTestServer();
builder.Services.AddSingleton();
await using var app = builder.Build();
@@ -1338,10 +1467,11 @@ public async Task StartupFilter_WithUseRoutingWorks()
Assert.Equal(203, ((int)response.StatusCode));
}
- [Fact]
- public async Task CanAddMiddlewareBeforeUseRouting()
+ [Theory]
+ [MemberData(nameof(CreateBuilderFuncs))]
+ public async Task CanAddMiddlewareBeforeUseRouting(CreateBuilderFunc createBuilder)
{
- var builder = WebApplication.CreateBuilder();
+ var builder = createBuilder();
builder.WebHost.UseTestServer();
await using var app = builder.Build();
@@ -1375,13 +1505,33 @@ public async Task CanAddMiddlewareBeforeUseRouting()
Assert.Equal("One", chosenEndpoint);
}
- [Fact]
- public async Task WebApplicationBuilder_OnlyAddsDefaultServicesOnce()
+ public static IEnumerable OnlyAddsDefaultServicesOnceData
{
- var builder = WebApplication.CreateBuilder();
+ get
+ {
+ // The slim builder doesn't add logging services by default
+ yield return new object[] { (CreateBuilderFunc)CreateBuilder, true };
+ yield return new object[] { (CreateBuilderFunc)CreateSlimBuilder, false };
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(OnlyAddsDefaultServicesOnceData))]
+ public async Task WebApplicationBuilder_OnlyAddsDefaultServicesOnce(CreateBuilderFunc createBuilder, bool hasLogging)
+ {
+ var builder = createBuilder();
// IWebHostEnvironment is added by ConfigureDefaults
- Assert.Single(builder.Services.Where(descriptor => descriptor.ServiceType == typeof(IConfigureOptions)));
+ var loggingDescriptors = builder.Services.Where(descriptor => descriptor.ServiceType == typeof(IConfigureOptions));
+ if (hasLogging)
+ {
+ Assert.Single(loggingDescriptors);
+ }
+ else
+ {
+ Assert.Empty(loggingDescriptors);
+ }
+
// IWebHostEnvironment is added by ConfigureWebHostDefaults
Assert.Single(builder.Services.Where(descriptor => descriptor.ServiceType == typeof(IWebHostEnvironment)));
Assert.Single(builder.Services.Where(descriptor => descriptor.ServiceType == typeof(IOptionsChangeTokenSource)));
@@ -1389,17 +1539,27 @@ public async Task WebApplicationBuilder_OnlyAddsDefaultServicesOnce()
await using var app = builder.Build();
- Assert.Single(app.Services.GetRequiredService>>());
+ var loggingServices = app.Services.GetRequiredService>>();
+ if (hasLogging)
+ {
+ Assert.Single(loggingServices);
+ }
+ else
+ {
+ Assert.Empty(loggingServices);
+ }
+
Assert.Single(app.Services.GetRequiredService>());
Assert.Single(app.Services.GetRequiredService>>());
Assert.Single(app.Services.GetRequiredService>());
}
- [Fact]
- public void WebApplicationBuilder_EnablesServiceScopeValidationByDefaultInDevelopment()
+ [Theory]
+ [MemberData(nameof(CreateBuilderArgsFuncs))]
+ public void WebApplicationBuilder_EnablesServiceScopeValidationByDefaultInDevelopment(CreateBuilderArgsFunc createBuilder)
{
// The environment cannot be reconfigured after the builder is created currently.
- var builder = WebApplication.CreateBuilder(new[] { "--environment", "Development" });
+ var builder = createBuilder(new[] { "--environment", "Development" });
builder.Services.AddScoped();
builder.Services.AddSingleton();
@@ -1409,10 +1569,11 @@ public void WebApplicationBuilder_EnablesServiceScopeValidationByDefaultInDevelo
Assert.ThrowsAny(() => builder.Build());
}
- [Fact]
- public async Task WebApplicationBuilder_ThrowsExceptionIfServicesAlreadyBuilt()
+ [Theory]
+ [MemberData(nameof(CreateBuilderFuncs))]
+ public async Task WebApplicationBuilder_ThrowsExceptionIfServicesAlreadyBuilt(CreateBuilderFunc createBuilder)
{
- var builder = WebApplication.CreateBuilder();
+ var builder = createBuilder();
await using var app = builder.Build();
Assert.Throws(() => builder.Services.AddSingleton(new Service()));
@@ -1423,10 +1584,11 @@ public async Task WebApplicationBuilder_ThrowsExceptionIfServicesAlreadyBuilt()
Assert.Throws(() => builder.Services[0] = ServiceDescriptor.Singleton(new Service()));
}
- [Fact]
- public void WebApplicationBuilder_ThrowsFromExtensionMethodsNotSupportedByHostAndWebHost()
+ [Theory]
+ [MemberData(nameof(CreateBuilderFuncs))]
+ public void WebApplicationBuilder_ThrowsFromExtensionMethodsNotSupportedByHostAndWebHost(CreateBuilderFunc createBuilder)
{
- var builder = WebApplication.CreateBuilder();
+ var builder = createBuilder();
var ex = Assert.Throws(() => builder.WebHost.Configure(app => { }));
var ex1 = Assert.Throws(() => builder.WebHost.Configure((context, app) => { }));
@@ -1442,17 +1604,20 @@ public void WebApplicationBuilder_ThrowsFromExtensionMethodsNotSupportedByHostAn
var ex5 = Assert.Throws(() => builder.Host.ConfigureWebHost(webHostBuilder => { }));
var ex6 = Assert.Throws(() => builder.Host.ConfigureWebHost(webHostBuilder => { }, options => { }));
- var ex7 = Assert.Throws(() => builder.Host.ConfigureWebHostDefaults(webHostBuilder => { }));
+ var ex7 = Assert.Throws(() => builder.Host.ConfigureSlimWebHost(webHostBuilder => { }, options => { }));
+ var ex8 = Assert.Throws(() => builder.Host.ConfigureWebHostDefaults(webHostBuilder => { }));
Assert.Equal("ConfigureWebHost() is not supported by WebApplicationBuilder.Host. Use the WebApplication returned by WebApplicationBuilder.Build() instead.", ex5.Message);
Assert.Equal("ConfigureWebHost() is not supported by WebApplicationBuilder.Host. Use the WebApplication returned by WebApplicationBuilder.Build() instead.", ex6.Message);
Assert.Equal("ConfigureWebHost() is not supported by WebApplicationBuilder.Host. Use the WebApplication returned by WebApplicationBuilder.Build() instead.", ex7.Message);
+ Assert.Equal("ConfigureWebHost() is not supported by WebApplicationBuilder.Host. Use the WebApplication returned by WebApplicationBuilder.Build() instead.", ex8.Message);
}
- [Fact]
- public async Task EndpointDataSourceOnlyAddsOnce()
+ [Theory]
+ [MemberData(nameof(CreateBuilderFuncs))]
+ public async Task EndpointDataSourceOnlyAddsOnce(CreateBuilderFunc createBuilder)
{
- var builder = WebApplication.CreateBuilder();
+ var builder = createBuilder();
await using var app = builder.Build();
app.UseRouting();
@@ -1474,10 +1639,11 @@ public async Task EndpointDataSourceOnlyAddsOnce()
Assert.Equal("Three", ds.Endpoints[2].DisplayName);
}
- [Fact]
- public async Task RoutesAddedToCorrectMatcher()
+ [Theory]
+ [MemberData(nameof(CreateBuilderFuncs))]
+ public async Task RoutesAddedToCorrectMatcher(CreateBuilderFunc createBuilder)
{
- var builder = WebApplication.CreateBuilder();
+ var builder = createBuilder();
builder.WebHost.UseTestServer();
await using var app = builder.Build();
@@ -1509,10 +1675,11 @@ public async Task RoutesAddedToCorrectMatcher()
Assert.Equal("One", chosenRoute);
}
- [Fact]
- public async Task WebApplication_CallsUseRoutingAndUseEndpoints()
+ [Theory]
+ [MemberData(nameof(CreateBuilderFuncs))]
+ public async Task WebApplication_CallsUseRoutingAndUseEndpoints(CreateBuilderFunc createBuilder)
{
- var builder = WebApplication.CreateBuilder();
+ var builder = createBuilder();
builder.WebHost.UseTestServer();
await using var app = builder.Build();
@@ -1535,10 +1702,11 @@ public async Task WebApplication_CallsUseRoutingAndUseEndpoints()
Assert.Equal("One", chosenRoute);
}
- [Fact]
- public async Task BranchingPipelineHasOwnRoutes()
+ [Theory]
+ [MemberData(nameof(CreateBuilderFuncs))]
+ public async Task BranchingPipelineHasOwnRoutes(CreateBuilderFunc createBuilder)
{
- var builder = WebApplication.CreateBuilder();
+ var builder = createBuilder();
builder.WebHost.UseTestServer();
await using var app = builder.Build();
@@ -1599,10 +1767,11 @@ public async Task BranchingPipelineHasOwnRoutes()
Assert.Equal("Four", chosenRoute);
}
- [Fact]
- public async Task PropertiesPreservedFromInnerApplication()
+ [Theory]
+ [MemberData(nameof(CreateBuilderFuncs))]
+ public async Task PropertiesPreservedFromInnerApplication(CreateBuilderFunc createBuilder)
{
- var builder = WebApplication.CreateBuilder();
+ var builder = createBuilder();
builder.Services.AddSingleton();
await using var app = builder.Build();
@@ -1611,10 +1780,11 @@ public async Task PropertiesPreservedFromInnerApplication()
app.Start();
}
- [Fact]
- public async Task DeveloperExceptionPageIsOnByDefaltInDevelopment()
+ [Theory]
+ [MemberData(nameof(CreateBuilderOptionsFuncs))]
+ public async Task DeveloperExceptionPageIsOnByDefaltInDevelopment(CreateBuilderOptionsFunc createBuilder)
{
- var builder = WebApplication.CreateBuilder(new WebApplicationOptions() { EnvironmentName = Environments.Development });
+ var builder = createBuilder(new WebApplicationOptions() { EnvironmentName = Environments.Development });
builder.WebHost.UseTestServer();
await using var app = builder.Build();
@@ -1632,10 +1802,11 @@ public async Task DeveloperExceptionPageIsOnByDefaltInDevelopment()
Assert.Contains("text/plain", response.Content.Headers.ContentType.MediaType);
}
- [Fact]
- public async Task DeveloperExceptionPageDoesNotGetCaughtByStartupFilters()
+ [Theory]
+ [MemberData(nameof(CreateBuilderOptionsFuncs))]
+ public async Task DeveloperExceptionPageDoesNotGetCaughtByStartupFilters(CreateBuilderOptionsFunc createBuilder)
{
- var builder = WebApplication.CreateBuilder(new WebApplicationOptions() { EnvironmentName = Environments.Development });
+ var builder = createBuilder(new WebApplicationOptions() { EnvironmentName = Environments.Development });
builder.WebHost.UseTestServer();
builder.Services.AddSingleton();
await using var app = builder.Build();
@@ -1649,10 +1820,11 @@ public async Task DeveloperExceptionPageDoesNotGetCaughtByStartupFilters()
Assert.Equal("BOOM Filter", ex.Message);
}
- [Fact]
- public async Task DeveloperExceptionPageIsNotOnInProduction()
+ [Theory]
+ [MemberData(nameof(CreateBuilderOptionsFuncs))]
+ public async Task DeveloperExceptionPageIsNotOnInProduction(CreateBuilderOptionsFunc createBuilder)
{
- var builder = WebApplication.CreateBuilder(new WebApplicationOptions() { EnvironmentName = Environments.Production });
+ var builder = createBuilder(new WebApplicationOptions() { EnvironmentName = Environments.Production });
builder.WebHost.UseTestServer();
await using var app = builder.Build();
@@ -1670,6 +1842,7 @@ public async Task DeveloperExceptionPageIsNotOnInProduction()
[Fact]
public async Task HostingStartupRunsWhenApplicationIsNotEntryPoint()
{
+ // NOTE: CreateSlimBuilder doesn't support Startups
var builder = WebApplication.CreateBuilder(new WebApplicationOptions { ApplicationName = typeof(WebApplicationTests).Assembly.FullName });
await using var app = builder.Build();
@@ -1679,6 +1852,7 @@ public async Task HostingStartupRunsWhenApplicationIsNotEntryPoint()
[Fact]
public async Task HostingStartupRunsWhenApplicationIsNotEntryPointWithArgs()
{
+ // NOTE: CreateSlimBuilder doesn't support Startups
var builder = WebApplication.CreateBuilder(new[] { "--applicationName", typeof(WebApplicationTests).Assembly.FullName });
await using var app = builder.Build();
@@ -1693,16 +1867,18 @@ public async Task HostingStartupRunsWhenApplicationIsNotEntryPointApplicationNam
Args = new[] { "--applicationName", typeof(WebApplication).Assembly.FullName },
ApplicationName = typeof(WebApplicationTests).Assembly.FullName,
};
+ // NOTE: CreateSlimBuilder doesn't support Startups
var builder = WebApplication.CreateBuilder(options);
await using var app = builder.Build();
Assert.Equal("value", app.Configuration["testhostingstartup:config"]);
}
- [Fact]
- public async Task DeveloperExceptionPageWritesBadRequestDetailsToResponseByDefaltInDevelopment()
+ [Theory]
+ [MemberData(nameof(CreateBuilderOptionsFuncs))]
+ public async Task DeveloperExceptionPageWritesBadRequestDetailsToResponseByDefaltInDevelopment(CreateBuilderOptionsFunc createBuilder)
{
- var builder = WebApplication.CreateBuilder(new WebApplicationOptions() { EnvironmentName = Environments.Development });
+ var builder = createBuilder(new WebApplicationOptions() { EnvironmentName = Environments.Development });
builder.WebHost.UseTestServer();
await using var app = builder.Build();
@@ -1723,10 +1899,11 @@ public async Task DeveloperExceptionPageWritesBadRequestDetailsToResponseByDefal
Assert.Contains("notAnInt", responseBody);
}
- [Fact]
- public async Task NoExceptionAreThrownForBadRequestsInProduction()
+ [Theory]
+ [MemberData(nameof(CreateBuilderOptionsFuncs))]
+ public async Task NoExceptionAreThrownForBadRequestsInProduction(CreateBuilderOptionsFunc createBuilder)
{
- var builder = WebApplication.CreateBuilder(new WebApplicationOptions() { EnvironmentName = Environments.Production });
+ var builder = createBuilder(new WebApplicationOptions() { EnvironmentName = Environments.Production });
builder.WebHost.UseTestServer();
await using var app = builder.Build();
@@ -1746,10 +1923,11 @@ public async Task NoExceptionAreThrownForBadRequestsInProduction()
Assert.Equal(string.Empty, responseBody);
}
- [Fact]
- public void PropertiesArePropagated()
+ [Theory]
+ [MemberData(nameof(CreateBuilderFuncs))]
+ public void PropertiesArePropagated(CreateBuilderFunc createBuilder)
{
- var builder = WebApplication.CreateBuilder();
+ var builder = createBuilder();
builder.Host.Properties["hello"] = "world";
var callbacks = 0;
@@ -1777,8 +1955,9 @@ public void PropertiesArePropagated()
Assert.Equal(0b00000111, callbacks);
}
- [Fact]
- public void EmptyAppConfiguration()
+ [Theory]
+ [MemberData(nameof(CreateBuilderFuncs))]
+ public void EmptyAppConfiguration(CreateBuilderFunc createBuilder)
{
var wwwroot = Path.Combine(AppContext.BaseDirectory, "wwwroot");
bool createdDirectory = false;
@@ -1790,7 +1969,7 @@ public void EmptyAppConfiguration()
try
{
- var builder = WebApplication.CreateBuilder();
+ var builder = createBuilder();
builder.WebHost.ConfigureAppConfiguration((ctx, config) => { });
@@ -1807,10 +1986,11 @@ public void EmptyAppConfiguration()
}
}
- [Fact]
- public void HostConfigurationNotAffectedByConfiguration()
+ [Theory]
+ [MemberData(nameof(CreateBuilderFuncs))]
+ public void HostConfigurationNotAffectedByConfiguration(CreateBuilderFunc createBuilder)
{
- var builder = WebApplication.CreateBuilder();
+ var builder = createBuilder();
var contentRoot = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
var envName = $"{nameof(WebApplicationTests)}_ENV";
@@ -1836,10 +2016,11 @@ public void HostConfigurationNotAffectedByConfiguration()
Assert.NotEqual(contentRoot, hostEnv.ContentRootPath);
}
- [Fact]
- public void ClearingConfigurationDoesNotAffectHostConfiguration()
+ [Theory]
+ [MemberData(nameof(CreateBuilderOptionsFuncs))]
+ public void ClearingConfigurationDoesNotAffectHostConfiguration(CreateBuilderOptionsFunc createBuilder)
{
- var builder = WebApplication.CreateBuilder(new WebApplicationOptions
+ var builder = createBuilder(new WebApplicationOptions
{
ApplicationName = typeof(WebApplicationOptions).Assembly.FullName,
EnvironmentName = Environments.Staging,
@@ -1865,10 +2046,11 @@ public void ClearingConfigurationDoesNotAffectHostConfiguration()
Assert.Equal(Path.GetTempPath(), hostEnv.ContentRootPath);
}
- [Fact]
- public void ConfigurationGetDebugViewWorks()
+ [Theory]
+ [MemberData(nameof(CreateBuilderFuncs))]
+ public void ConfigurationGetDebugViewWorks(CreateBuilderFunc createBuilder)
{
- var builder = WebApplication.CreateBuilder();
+ var builder = createBuilder();
builder.Configuration.AddInMemoryCollection(new Dictionary
{
@@ -1881,10 +2063,11 @@ public void ConfigurationGetDebugViewWorks()
Assert.Contains("foo=bar (MemoryConfigurationProvider)", ((IConfigurationRoot)app.Configuration).GetDebugView());
}
- [Fact]
- public void ConfigurationCanBeReloaded()
+ [Theory]
+ [MemberData(nameof(CreateBuilderFuncs))]
+ public void ConfigurationCanBeReloaded(CreateBuilderFunc createBuilder)
{
- var builder = WebApplication.CreateBuilder();
+ var builder = createBuilder();
((IConfigurationBuilder)builder.Configuration).Sources.Add(new RandomConfigurationSource());
@@ -1897,10 +2080,11 @@ public void ConfigurationCanBeReloaded()
Assert.NotEqual(value0, value1);
}
- [Fact]
- public void ConfigurationSourcesAreBuiltOnce()
+ [Theory]
+ [MemberData(nameof(CreateBuilderFuncs))]
+ public void ConfigurationSourcesAreBuiltOnce(CreateBuilderFunc createBuilder)
{
- var builder = WebApplication.CreateBuilder();
+ var builder = createBuilder();
var configSource = new RandomConfigurationSource();
((IConfigurationBuilder)builder.Configuration).Sources.Add(configSource);
@@ -1910,10 +2094,11 @@ public void ConfigurationSourcesAreBuiltOnce()
Assert.Equal(1, configSource.ProvidersBuilt);
}
- [Fact]
- public void ConfigurationProvidersAreLoadedOnceAfterBuild()
+ [Theory]
+ [MemberData(nameof(CreateBuilderFuncs))]
+ public void ConfigurationProvidersAreLoadedOnceAfterBuild(CreateBuilderFunc createBuilder)
{
- var builder = WebApplication.CreateBuilder();
+ var builder = createBuilder();
var configSource = new RandomConfigurationSource();
((IConfigurationBuilder)builder.Configuration).Sources.Add(configSource);
@@ -1923,10 +2108,11 @@ public void ConfigurationProvidersAreLoadedOnceAfterBuild()
Assert.Equal(1, configSource.ProvidersLoaded);
}
- [Fact]
- public void ConfigurationProvidersAreDisposedWithWebApplication()
+ [Theory]
+ [MemberData(nameof(CreateBuilderFuncs))]
+ public void ConfigurationProvidersAreDisposedWithWebApplication(CreateBuilderFunc createBuilder)
{
- var builder = WebApplication.CreateBuilder();
+ var builder = createBuilder();
var configSource = new RandomConfigurationSource();
((IConfigurationBuilder)builder.Configuration).Sources.Add(configSource);
@@ -1940,10 +2126,11 @@ public void ConfigurationProvidersAreDisposedWithWebApplication()
Assert.Equal(1, configSource.ProvidersDisposed);
}
- [Fact]
- public void ConfigurationProviderTypesArePreserved()
+ [Theory]
+ [MemberData(nameof(CreateBuilderFuncs))]
+ public void ConfigurationProviderTypesArePreserved(CreateBuilderFunc createBuilder)
{
- var builder = WebApplication.CreateBuilder();
+ var builder = createBuilder();
((IConfigurationBuilder)builder.Configuration).Sources.Add(new RandomConfigurationSource());
@@ -1952,10 +2139,11 @@ public void ConfigurationProviderTypesArePreserved()
Assert.Single(((IConfigurationRoot)app.Configuration).Providers.OfType());
}
- [Fact]
- public async Task CanUseMiddleware()
+ [Theory]
+ [MemberData(nameof(CreateBuilderFuncs))]
+ public async Task CanUseMiddleware(CreateBuilderFunc createBuilder)
{
- var builder = WebApplication.CreateBuilder();
+ var builder = createBuilder();
builder.WebHost.UseTestServer();
await using var app = builder.Build();
@@ -1972,10 +2160,11 @@ public async Task CanUseMiddleware()
Assert.Equal("Hello World", response);
}
- [Fact]
- public void CanObserveDefaultServicesInServiceCollection()
+ [Theory]
+ [MemberData(nameof(CreateBuilderFuncs))]
+ public void CanObserveDefaultServicesInServiceCollection(CreateBuilderFunc createBuilder)
{
- var builder = WebApplication.CreateBuilder();
+ var builder = createBuilder();
Assert.Contains(builder.Services, service => service.ServiceType == typeof(HostBuilderContext));
Assert.Contains(builder.Services, service => service.ServiceType == typeof(IHostApplicationLifetime));
@@ -1985,20 +2174,32 @@ public void CanObserveDefaultServicesInServiceCollection()
Assert.Contains(builder.Services, service => service.ServiceType == typeof(ILogger<>));
}
- [Fact]
- public async Task RegisterAuthMiddlewaresCorrectly()
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public async Task RegisterAuthMiddlewaresCorrectly(bool useSlimBuilder)
{
var helloEndpointCalled = false;
var customMiddlewareExecuted = false;
var username = "foobar";
- var builder = WebApplication.CreateBuilder();
+ var builder = useSlimBuilder ?
+ WebApplication.CreateSlimBuilder() :
+ WebApplication.CreateBuilder();
+
builder.Services.AddAuthorization();
builder.Services.AddAuthentication("testSchemeName")
.AddScheme("testSchemeName", "testDisplayName", _ => { });
builder.WebHost.UseTestServer();
await using var app = builder.Build();
+ if (useSlimBuilder)
+ {
+ // NOTE: CreateSlimBuilder doesn't support auto registration of auth middleware, so need to do it explicitly
+ app.UseAuthentication();
+ app.UseAuthorization();
+ }
+
app.Use(next =>
{
return async context =>
@@ -2031,6 +2232,7 @@ public async Task RegisterAuthMiddlewaresCorrectly()
[Fact]
public async Task SupportsDisablingMiddlewareAutoRegistration()
{
+ // NOTE: CreateSlimBuilder doesn't support auto registration of auth middleware
var builder = WebApplication.CreateBuilder();
builder.Services.AddAuthorization();
builder.Services.AddAuthentication("testSchemeName")
diff --git a/src/Hosting/Hosting/src/GenericHost/GenericWebHostBuilder.cs b/src/Hosting/Hosting/src/GenericHost/GenericWebHostBuilder.cs
index 0116dd0c8410..d89ddfe9331c 100644
--- a/src/Hosting/Hosting/src/GenericHost/GenericWebHostBuilder.cs
+++ b/src/Hosting/Hosting/src/GenericHost/GenericWebHostBuilder.cs
@@ -18,10 +18,8 @@
namespace Microsoft.AspNetCore.Hosting;
-internal sealed class GenericWebHostBuilder : IWebHostBuilder, ISupportsStartup, ISupportsUseDefaultServiceProvider
+internal sealed class GenericWebHostBuilder : WebHostBuilderBase, ISupportsStartup
{
- private readonly IHostBuilder _builder;
- private readonly IConfiguration _config;
private object? _startupObject;
private readonly object _startupKey = new object();
@@ -29,18 +27,8 @@ internal sealed class GenericWebHostBuilder : IWebHostBuilder, ISupportsStartup,
private HostingStartupWebHostBuilder? _hostingStartupWebHostBuilder;
public GenericWebHostBuilder(IHostBuilder builder, WebHostBuilderOptions options)
+ : base(builder, options)
{
- _builder = builder;
- var configBuilder = new ConfigurationBuilder()
- .AddInMemoryCollection();
-
- if (!options.SuppressEnvironmentConfiguration)
- {
- configBuilder.AddEnvironmentVariables(prefix: "ASPNETCORE_");
- }
-
- _config = configBuilder.Build();
-
_builder.ConfigureHostConfiguration(config =>
{
config.AddConfiguration(_config);
@@ -172,51 +160,6 @@ private void ExecuteHostingStartups()
}
}
- 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)
- {
- _builder.UseServiceProviderFactory(context =>
- {
- var webHostBuilderContext = GetWebHostBuilderContext(context);
- var options = new ServiceProviderOptions();
- configure(webHostBuilderContext, options);
- return new DefaultServiceProviderFactory(options);
- });
-
- return this;
- }
-
public IWebHostBuilder UseStartup([DynamicallyAccessedMembers(StartupLinkerOptions.Accessibility)] Type startupType)
{
var startupAssemblyName = startupType.Assembly.GetName().Name;
@@ -412,40 +355,6 @@ public IWebHostBuilder Configure(Action
+ {
+ config.AddConfiguration(_config);
+ });
+
+ _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);
+#pragma warning disable CS0618 // Type or member is obsolete
+ services.AddSingleton((AspNetCore.Hosting.IHostingEnvironment)webhostContext.HostingEnvironment);
+ services.AddSingleton();
+#pragma warning restore CS0618 // Type or member is obsolete
+
+ services.Configure(options =>
+ {
+ // Set the options
+ options.WebHostOptions = webHostOptions;
+ });
+
+ // 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
+ services.TryAddSingleton(sp => new DiagnosticListener("Microsoft.AspNetCore"));
+ services.TryAddSingleton(sp => sp.GetRequiredService());
+ services.TryAddSingleton(sp => new ActivitySource("Microsoft.AspNetCore"));
+ services.TryAddSingleton(DistributedContextPropagator.Current);
+
+ services.TryAddSingleton();
+ services.TryAddScoped();
+ services.TryAddSingleton();
+ });
+ }
+
+ public IWebHostBuilder Configure(Action configure)
+ {
+ throw new NotSupportedException();
+ }
+
+ public IWebHostBuilder UseStartup([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.PublicMethods)] Type startupType)
+ {
+ throw new NotSupportedException();
+ }
+
+ public IWebHostBuilder UseStartup<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] TStartup>(Func startupFactory)
+ {
+ throw new NotSupportedException();
+ }
+
+ public IWebHostBuilder Configure(Action configure)
+ {
+ var startupAssemblyName = configure.GetMethodInfo().DeclaringType!.Assembly.GetName().Name!;
+
+ UseSetting(WebHostDefaults.ApplicationKey, startupAssemblyName);
+
+ _builder.ConfigureServices((context, services) =>
+ {
+ services.Configure(options =>
+ {
+ var webhostBuilderContext = GetWebHostBuilderContext(context);
+ options.ConfigureApplication = app => configure(webhostBuilderContext, app);
+ });
+ });
+
+ return this;
+ }
+}
diff --git a/src/Hosting/Hosting/src/GenericHost/WebHostBuilderBase.cs b/src/Hosting/Hosting/src/GenericHost/WebHostBuilderBase.cs
new file mode 100644
index 000000000000..c104ed40002a
--- /dev/null
+++ b/src/Hosting/Hosting/src/GenericHost/WebHostBuilderBase.cs
@@ -0,0 +1,107 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+
+namespace Microsoft.AspNetCore.Hosting;
+
+internal abstract class WebHostBuilderBase : IWebHostBuilder, ISupportsUseDefaultServiceProvider
+{
+ private protected readonly IHostBuilder _builder;
+ private protected readonly IConfiguration _config;
+
+ public WebHostBuilderBase(IHostBuilder builder, WebHostBuilderOptions options)
+ {
+ _builder = builder;
+ var configBuilder = new ConfigurationBuilder()
+ .AddInMemoryCollection();
+
+ if (!options.SuppressEnvironmentConfiguration)
+ {
+ configBuilder.AddEnvironmentVariables(prefix: "ASPNETCORE_");
+ }
+
+ _config = configBuilder.Build();
+ }
+
+ 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)
+ {
+ _builder.UseServiceProviderFactory(context =>
+ {
+ var webHostBuilderContext = GetWebHostBuilderContext(context);
+ var options = new ServiceProviderOptions();
+ configure(webHostBuilderContext, options);
+ return new DefaultServiceProviderFactory(options);
+ });
+
+ return this;
+ }
+
+ protected WebHostBuilderContext GetWebHostBuilderContext(HostBuilderContext context)
+ {
+ if (!context.Properties.TryGetValue(typeof(WebHostBuilderContext), out var contextVal))
+ {
+ // Use _config as a fallback for WebHostOptions in case the chained source was removed from the hosting IConfigurationBuilder.
+ var options = new WebHostOptions(context.Configuration, fallbackConfiguration: _config, environment: context.HostingEnvironment);
+ var webHostBuilderContext = new WebHostBuilderContext
+ {
+ Configuration = context.Configuration,
+ HostingEnvironment = new HostingEnvironment(),
+ };
+ webHostBuilderContext.HostingEnvironment.Initialize(context.HostingEnvironment.ContentRootPath, options, baseEnvironment: context.HostingEnvironment);
+ context.Properties[typeof(WebHostBuilderContext)] = webHostBuilderContext;
+ context.Properties[typeof(WebHostOptions)] = options;
+ return webHostBuilderContext;
+ }
+
+ // Refresh config, it's periodically updated/replaced
+ var webHostContext = (WebHostBuilderContext)contextVal;
+ webHostContext.Configuration = context.Configuration;
+ return webHostContext;
+ }
+
+ public string? GetSetting(string key)
+ {
+ return _config[key];
+ }
+
+ public IWebHostBuilder UseSetting(string key, string? value)
+ {
+ _config[key] = value;
+ return this;
+ }
+}
diff --git a/src/Hosting/Hosting/src/GenericHostWebHostBuilderExtensions.cs b/src/Hosting/Hosting/src/GenericHostWebHostBuilderExtensions.cs
index 7bd6f86a49af..ea37f73aa036 100644
--- a/src/Hosting/Hosting/src/GenericHostWebHostBuilderExtensions.cs
+++ b/src/Hosting/Hosting/src/GenericHostWebHostBuilderExtensions.cs
@@ -33,6 +33,35 @@ public static IHostBuilder ConfigureWebHost(this IHostBuilder builder, ActionThe delegate that configures the .
/// The .
public static IHostBuilder ConfigureWebHost(this IHostBuilder builder, Action configure, Action configureWebHostBuilder)
+ {
+ return ConfigureWebHost(
+ builder,
+ static (hostBuilder, options) => new GenericWebHostBuilder(hostBuilder, options),
+ configure,
+ configureWebHostBuilder);
+ }
+
+ ///
+ /// Adds and configures an ASP.NET Core web application with minimal dependencies.
+ ///
+ /// The to add the to.
+ /// The delegate that configures the .
+ /// The delegate that configures the .
+ /// The .
+ public static IHostBuilder ConfigureSlimWebHost(this IHostBuilder builder, Action configure, Action configureWebHostBuilder)
+ {
+ return ConfigureWebHost(
+ builder,
+ static (hostBuilder, options) => new SlimWebHostBuilder(hostBuilder, options),
+ configure,
+ configureWebHostBuilder);
+ }
+
+ private static IHostBuilder ConfigureWebHost(
+ this IHostBuilder builder,
+ Func createWebHostBuilder,
+ Action configure,
+ Action configureWebHostBuilder)
{
ArgumentNullException.ThrowIfNull(configure);
ArgumentNullException.ThrowIfNull(configureWebHostBuilder);
@@ -45,7 +74,7 @@ public static IHostBuilder ConfigureWebHost(this IHostBuilder builder, Action services.AddHostedService());
return builder;
diff --git a/src/Hosting/Hosting/src/PublicAPI.Unshipped.txt b/src/Hosting/Hosting/src/PublicAPI.Unshipped.txt
index 7dc5c58110bf..de9a58f9e603 100644
--- a/src/Hosting/Hosting/src/PublicAPI.Unshipped.txt
+++ b/src/Hosting/Hosting/src/PublicAPI.Unshipped.txt
@@ -1 +1,2 @@
#nullable enable
+static Microsoft.Extensions.Hosting.GenericHostWebHostBuilderExtensions.ConfigureSlimWebHost(this Microsoft.Extensions.Hosting.IHostBuilder! builder, System.Action! configure, System.Action! configureWebHostBuilder) -> Microsoft.Extensions.Hosting.IHostBuilder!
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/Program.Main.cs b/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/Program.Main.cs
index 1e7082c4f9cb..dc6deae4de45 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/Program.Main.cs
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/Program.Main.cs
@@ -9,7 +9,7 @@ public class Program
{
public static void Main(string[] args)
{
- var builder = WebApplication.CreateBuilder(args);
+ var builder = WebApplication.CreateSlimBuilder(args);
builder.Logging.AddConsole();
#if (NativeAot)
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/Program.cs b/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/Program.cs
index be0ffccde6fa..5f12bdd3c5ba 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/Program.cs
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/Api-CSharp/Program.cs
@@ -3,7 +3,7 @@
#endif
using Company.ApiApplication1;
-var builder = WebApplication.CreateBuilder(args);
+var builder = WebApplication.CreateSlimBuilder(args);
builder.Logging.AddConsole();
#if (NativeAot)