-
Notifications
You must be signed in to change notification settings - Fork 10.3k
Allow minimal host to be created without default HostBuilder behavior #46040
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
83c4bd8
743349d
ef62c6d
2073eeb
2216e6e
0a58daa
1df7185
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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! |
Original file line number | Diff line number | Diff line change | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -86,6 +86,97 @@ internal WebApplicationBuilder(WebApplicationOptions options, Action<IHostBuilde | |||||||||||
WebHost = new ConfigureWebHostBuilder(webHostContext, Configuration, Services); | ||||||||||||
} | ||||||||||||
|
||||||||||||
internal WebApplicationBuilder(WebApplicationOptions options, bool slim, Action<IHostBuilder>? 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, | ||||||||||||
halter73 marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||
}); | ||||||||||||
|
||||||||||||
// 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<string, string?>(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; | ||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We have not already applied "ASPNETCORE_" environment variables to hosting config in this code path. Only "DOTNET_". We should do both. I bet this is why the macOS template test is failing to load the server certificate. We had an issue a while back with the template tests using expired dev certs on macOS. That was fixed by using "ASPNETCORE_"-prefixed environment variables to set a default cert, so the tests shouldn't rely on the development cert being up to date. aspnetcore/src/ProjectTemplates/Shared/AspNetProcess.cs Lines 91 to 95 in 40dd230
I'm guessing the dev cert is working as a fallback on the other OS's, but we still have that original issue on macOS when it falls back to the dev cert. @adityamandaleeka I wonder if this is related to our wider macOS dev cert issues. |
||||||||||||
}); | ||||||||||||
|
||||||||||||
// 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(); | ||||||||||||
} | ||||||||||||
|
||||||||||||
/// <summary> | ||||||||||||
/// Provides information about the web hosting environment an application is running. | ||||||||||||
/// </summary> | ||||||||||||
|
@@ -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<IServiceProviderIsService>(); | ||||||||||||
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<IServiceProviderIsService>(); | ||||||||||||
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 => | ||||||||||||
|
Uh oh!
There was an error while loading. Please reload this page.