这里可以发现执行顺序和我们的代码的书写顺序并不是一致的。
那么我们再次做一个小小的调换,那么会怎么样呢?
public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { Console.WriteLine("ConfigureWebHostDefaults"); webBuilder.UseStartup<Startup>(); }) .ConfigureServices(builder => { Console.WriteLine("ConfigureServices"); }) .ConfigureAppConfiguration((builder) => { Console.WriteLine("ConfigureAppConfiguration"); }) .ConfigureHostConfiguration(builder => { Console.WriteLine("ConfigureHostConfiguration"); }); }发现变化的只有Startup.ConfigureServices 和 ConfigureServices。
这个时候我们大体猜出来了这个启动顺序是按照某种执行顺序执行,且Startup.ConfigureServices 和 ConfigureServices 是同一种类型,并且他们的执行顺序和他们的注册顺序保持一致。
执行顺序如下:
先看一下CreateDefaultBuilder:
public static IHostBuilder CreateDefaultBuilder(string[] args) { var builder = new HostBuilder(); builder.UseContentRoot(Directory.GetCurrentDirectory()); builder.ConfigureHostConfiguration(config => { config.AddEnvironmentVariables(prefix: "DOTNET_"); if (args != null) { config.AddCommandLine(args); } }); builder.ConfigureAppConfiguration((hostingContext, config) => { var env = hostingContext.HostingEnvironment; config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true); if (env.IsDevelopment() && !string.IsNullOrEmpty(env.ApplicationName)) { var appAssembly = Assembly.Load(new AssemblyName(env.ApplicationName)); if (appAssembly != null) { config.AddUserSecrets(appAssembly, optional: true); } } config.AddEnvironmentVariables(); if (args != null) { config.AddCommandLine(args); } }) .ConfigureLogging((hostingContext, logging) => { var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); // IMPORTANT: This needs to be added *before* configuration is loaded, this lets // the defaults be overridden by the configuration. if (isWindows) { // Default the EventLogLoggerProvider to warning or above logging.AddFilter<EventLogLoggerProvider>(level => level >= LogLevel.Warning); } logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging")); logging.AddConsole(); logging.AddDebug(); logging.AddEventSourceLogger(); if (isWindows) { // Add the EventLogLoggerProvider on windows machines logging.AddEventLog(); } }) .UseDefaultServiceProvider((context, options) => { var isDevelopment = context.HostingEnvironment.IsDevelopment(); options.ValidateScopes = isDevelopment; options.ValidateOnBuild = isDevelopment; }); return builder; }那么先看下ConfigureWebDefaults 到底干了什么。
internal static void ConfigureWebDefaults(IWebHostBuilder builder) { builder.ConfigureAppConfiguration((ctx, cb) => { if (ctx.HostingEnvironment.IsDevelopment()) { StaticWebAssetsLoader.UseStaticWebAssets(ctx.HostingEnvironment, ctx.Configuration); } }); builder.UseKestrel((builderContext, options) => { options.Configure(builderContext.Configuration.GetSection("Kestrel")); }) .ConfigureServices((hostingContext, services) => { // Fallback services.PostConfigure<HostFilteringOptions>(options => { if (options.AllowedHosts == null || options.AllowedHosts.Count == 0) { // "AllowedHosts": "localhost;127.0.0.1;[::1]" var hosts = hostingContext.Configuration["AllowedHosts"]?.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries); // Fall back to "*" to disable. options.AllowedHosts = (hosts?.Length > 0 ? hosts : new[] { "*" }); } }); // Change notification services.AddSingleton<IOptionsChangeTokenSource<HostFilteringOptions>>( new ConfigurationChangeTokenSource<HostFilteringOptions>(hostingContext.Configuration)); services.AddTransient<IStartupFilter, HostFilteringStartupFilter>(); if (string.Equals("true", hostingContext.Configuration["ForwardedHeaders_Enabled"], StringComparison.OrdinalIgnoreCase)) { services.Configure<ForwardedHeadersOptions>(options => { options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto; // Only loopback proxies are allowed by default. Clear that restriction because forwarders are // being enabled by explicit configuration. options.KnownNetworks.Clear(); options.KnownProxies.Clear(); }); services.AddTransient<IStartupFilter, ForwardedHeadersStartupFilter>(); } services.AddRouting(); }) .UseIIS() .UseIISIntegration(); }ConfigureWebDefaults 配置了一些必要的组件。
CreateDefaultBuilder 和 ConfigureWebDefaults 两者可以看到其实就是做一些默认配置让我们的服务能够启动起来。
而后续的配置也就是注册的顺序执行,只是我们的执行顺序晚点罢了。
那么再整理一下,也就是说从原理的执行顺序来说是这样的。
ConfigureHostConfiguration ConfigureAppConfiguration ConfigureServices ConfigureLogging Configure