webapplication.createBuilder一些记录

发布时间 2023-05-27 17:02:38作者: 斯蒂芬斯
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();
    }

后续再补。。。