webapplication.createBuilder一些记录
internal WebApplicationBuilder(WebApplicationOptions options, Action<IHostBuilder>? configureDefaults = null) { var configuration = new ConfigurationManager(); configuration.AddEnvironmentVariables(prefix: "ASPNETCORE_"); _hostApplicationBuilder = new HostApplicationBuilder(new HostApplicationBuilderSettings { Args = options.Args, ApplicationName = options.ApplicationName, EnvironmentName = options.EnvironmentName, ContentRootPath = options.ContentRootPath, Configuration = configuration, }); // 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.ConfigureWebHostDefaults(webHostBuilder => { // Runs inline. webHostBuilder.Configure(ConfigureApplication); 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); }
先看下WebApplicationOptions的源码:
namespace Microsoft.AspNetCore.Builder; /// <summary> /// Options for configuring the behavior for <see cref="WebApplication.CreateBuilder(WebApplicationOptions)"/>. /// </summary> public class WebApplicationOptions { /// <summary> /// The command line arguments. /// </summary> public string[]? Args { get; init; } /// <summary> /// The environment name. /// </summary> public string? EnvironmentName { get; init; } /// <summary> /// The application name. /// </summary> public string? ApplicationName { get; init; } /// <summary> /// The content root path. /// </summary> public string? ContentRootPath { get; init; } /// <summary> /// The web root path. /// </summary> public string? WebRootPath { get; init; } }
看下:
var configuration = new ConfigurationManager();
源码如下:
public ConfigurationManager() { _sources = new ConfigurationSources(this); _properties = new ConfigurationBuilderProperties(this); // Make sure there's some default storage since there are no default providers. _sources.Add(new MemoryConfigurationSource()); }
第二步:生成BootstrapHostBuilder, 参数HostApplicationBuilder,是从上面实例化时传递过来的。
public BootstrapHostBuilder(HostApplicationBuilder builder) { _builder = builder; foreach (var descriptor in _builder.Services) { if (descriptor.ServiceType == typeof(HostBuilderContext)) { Context = (HostBuilderContext)descriptor.ImplementationInstance!; break; } } if (Context is null) { throw new InvalidOperationException($"{nameof(HostBuilderContext)} must exist in the {nameof(IServiceCollection)}"); } }
namespace Microsoft.Extensions.Hosting { /// <summary> /// A builder for hosted applications and services which helps manage configuration, logging, lifetime and more. /// </summary> public sealed class HostApplicationBuilder { private readonly HostBuilderContext _hostBuilderContext; private readonly ServiceCollection _serviceCollection = new(); private readonly IHostEnvironment _environment; private readonly LoggingBuilder _logging; private Func<IServiceProvider> _createServiceProvider; private Action<object> _configureContainer = _ => { }; private HostBuilderAdapter? _hostBuilderAdapter; private IServiceProvider? _appServices; private bool _hostBuilt; /// <summary> /// Initializes a new instance of the <see cref="HostApplicationBuilder"/>. /// </summary> /// <param name="settings">Settings controlling initial configuration and whether default settings should be used.</param> public HostApplicationBuilder(HostApplicationBuilderSettings? settings) { settings ??= new HostApplicationBuilderSettings(); Configuration = settings.Configuration ?? new ConfigurationManager(); if (!settings.DisableDefaults) { if (settings.ContentRootPath is null && Configuration[HostDefaults.ContentRootKey] is null) { HostingHostBuilderExtensions.SetDefaultContentRoot(Configuration); } Configuration.AddEnvironmentVariables(prefix: "DOTNET_"); } Initialize(settings, out _hostBuilderContext, out _environment, out _logging); ServiceProviderOptions? serviceProviderOptions = null; if (!settings.DisableDefaults) { HostingHostBuilderExtensions.ApplyDefaultAppConfiguration(_hostBuilderContext, Configuration, settings.Args); HostingHostBuilderExtensions.AddDefaultServices(_hostBuilderContext, Services); serviceProviderOptions = HostingHostBuilderExtensions.CreateDefaultServiceProviderOptions(_hostBuilderContext); } _createServiceProvider = () => { // Call _configureContainer in case anyone adds callbacks via HostBuilderAdapter.ConfigureContainer<IServiceCollection>() during build. // Otherwise, this no-ops. _configureContainer(Services); return serviceProviderOptions is null ? Services.BuildServiceProvider() : Services.BuildServiceProvider(serviceProviderOptions); }; }
private void Initialize(HostApplicationBuilderSettings settings, out HostBuilderContext hostBuilderContext, out IHostEnvironment environment, out LoggingBuilder logging) { // Command line args are added even when settings.DisableDefaults == true. If the caller didn't want settings.Args applied, // they wouldn't have set them on the settings. HostingHostBuilderExtensions.AddCommandLineConfig(Configuration, settings.Args); // HostApplicationBuilderSettings override all other config sources. List<KeyValuePair<string, string?>>? optionList = null; if (settings.ApplicationName is not null) { optionList ??= new List<KeyValuePair<string, string?>>(); optionList.Add(new KeyValuePair<string, string?>(HostDefaults.ApplicationKey, settings.ApplicationName)); } if (settings.EnvironmentName is not null) { optionList ??= new List<KeyValuePair<string, string?>>(); optionList.Add(new KeyValuePair<string, string?>(HostDefaults.EnvironmentKey, settings.EnvironmentName)); } if (settings.ContentRootPath is not null) { optionList ??= new List<KeyValuePair<string, string?>>(); optionList.Add(new KeyValuePair<string, string?>(HostDefaults.ContentRootKey, settings.ContentRootPath)); } if (optionList is not null) { Configuration.AddInMemoryCollection(optionList); } (HostingEnvironment hostingEnvironment, PhysicalFileProvider physicalFileProvider) = HostBuilder.CreateHostingEnvironment(Configuration); Configuration.SetFileProvider(physicalFileProvider); hostBuilderContext = new HostBuilderContext(new Dictionary<object, object>()) { HostingEnvironment = hostingEnvironment, Configuration = Configuration, }; environment = hostingEnvironment; HostBuilder.PopulateServiceCollection( Services, hostBuilderContext, hostingEnvironment, physicalFileProvider, Configuration, () => _appServices!); logging = new LoggingBuilder(Services); }
}
看一下这个方法:
internal static (HostingEnvironment, PhysicalFileProvider) CreateHostingEnvironment(IConfiguration hostConfiguration) { var hostingEnvironment = new HostingEnvironment() { EnvironmentName = hostConfiguration[HostDefaults.EnvironmentKey] ?? Environments.Production, ContentRootPath = ResolveContentRootPath(hostConfiguration[HostDefaults.ContentRootKey], AppContext.BaseDirectory), }; string? applicationName = hostConfiguration[HostDefaults.ApplicationKey]; if (string.IsNullOrEmpty(applicationName)) { // Note GetEntryAssembly returns null for the net4x console test runner. applicationName = Assembly.GetEntryAssembly()?.GetName().Name; } if (applicationName is not null) { hostingEnvironment.ApplicationName = applicationName; } var physicalFileProvider = new PhysicalFileProvider(hostingEnvironment.ContentRootPath); hostingEnvironment.ContentRootFileProvider = physicalFileProvider; return (hostingEnvironment, physicalFileProvider); }
再看一个封装类:
namespace Microsoft.Extensions.Hosting { /// <summary> /// Constants for HostBuilder configuration keys. /// </summary> public static class HostDefaults { /// <summary> /// The configuration key used to set <see cref="IHostEnvironment.ApplicationName"/>. /// </summary> public static readonly string ApplicationKey = "applicationName"; /// <summary> /// The configuration key used to set <see cref="IHostEnvironment.EnvironmentName"/>. /// </summary> public static readonly string EnvironmentKey = "environment"; /// <summary> /// The configuration key used to set <see cref="IHostEnvironment.ContentRootPath"/> /// and <see cref="IHostEnvironment.ContentRootFileProvider"/>. /// </summary> public static readonly string ContentRootKey = "contentRoot"; } }
接下来:
public static IHostBuilder ConfigureWebHostDefaults(this IHostBuilder builder, Action<IWebHostBuilder> configure, Action<WebHostBuilderOptions> configureOptions) { ArgumentNullException.ThrowIfNull(configure); return builder.ConfigureWebHost(webHostBuilder => { WebHost.ConfigureWebDefaults(webHostBuilder); configure(webHostBuilder); }, configureOptions); }
internal static void ConfigureWebDefaults(IWebHostBuilder builder) { builder.ConfigureAppConfiguration((ctx, cb) => { if (ctx.HostingEnvironment.IsDevelopment()) { StaticWebAssetsLoader.UseStaticWebAssets(ctx.HostingEnvironment, ctx.Configuration); } }); ConfigureWebDefaultsWorker( builder.UseKestrel(ConfigureKestrel), services => { services.AddRouting(); }); builder .UseIIS() .UseIISIntegration(); }
后续再补。。。