ASP.NET Core基础1:应用启动流程

先看下ASP.NET Core的启动代码,如下图:


image

通过以上代码,我们可以初步得出以下结论:

  • 所有的ASP.NET Core程序本质上也是一个控制台程序,使用Program的Main方法作为程序的入口。
  • 控制台Main入口-->IWebHostBuilder-->IWebHost-->Run,发现本质上就是启动一个作为宿主的Host。
  • 下面结合源码代详细分析下。

    宿主构造器:IWebHostBuilder

    看下WebHost的静态方法CreateDefaultBuilder的源码。

    /// <summary>
            /// Initializes a new instance of the <see cref="WebHostBuilder"/> class with pre-configured defaults.
            /// </summary>
            /// <remarks>
            ///   The following defaults are applied to the returned <see cref="WebHostBuilder"/>:
            ///     use Kestrel as the web server and configure it using the application's configuration providers,
            ///     set the <see cref="IHostingEnvironment.ContentRootPath"/> to the result of <see cref="Directory.GetCurrentDirectory()"/>,
            ///     load <see cref="IConfiguration"/> from 'appsettings.json' and 'appsettings.[<see cref="IHostingEnvironment.EnvironmentName"/>].json',
            ///     load <see cref="IConfiguration"/> from User Secrets when <see cref="IHostingEnvironment.EnvironmentName"/> is 'Development' using the entry assembly,
            ///     load <see cref="IConfiguration"/> from environment variables,
            ///     load <see cref="IConfiguration"/> from supplied command line args,
            ///     configure the <see cref="ILoggerFactory"/> to log to the console and debug output,
            ///     and enable IIS integration.
            /// </remarks>
            /// <param name="args">The command line args.</param>
            /// <returns>The initialized <see cref="IWebHostBuilder"/>.</returns>
            public static IWebHostBuilder CreateDefaultBuilder(string[] args)
            {
                var builder = new WebHostBuilder();
    
                if (string.IsNullOrEmpty(builder.GetSetting(WebHostDefaults.ContentRootKey)))
                {
                    builder.UseContentRoot(Directory.GetCurrentDirectory());
                }
                if (args != null)
                {
                    builder.UseConfiguration(new ConfigurationBuilder().AddCommandLine(args).Build());
                }
    
                builder.UseKestrel((builderContext, options) =>
                    {
                        options.Configure(builderContext.Configuration.GetSection("Kestrel"));
                    })
                    .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())
                        {
                            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) =>
                    {
                        logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
                        logging.AddConsole();
                        logging.AddDebug();
                        logging.AddEventSourceLogger();
                    })
                    .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>();
                    })
                    .UseIIS()
                    .UseIISIntegration()
                    .UseDefaultServiceProvider((context, options) =>
                    {
                        options.ValidateScopes = context.HostingEnvironment.IsDevelopment();
                    });
    
                return builder;
            }

    1,UseContentRoot

    指定Web host使用的内容根目录,比如Views。默认为当前应用程序根目录。


    2,UseConfiguration

    //todo


    3,UseKestrel

    使用Kestrel作为默认的Web Server。


    4,ConfigureAppConfiguration

    设置当前应用程序配置。主要是读取 appsettings.json配置文件、开发环境中配置的UserSecrets、添加环境变量和命令行参数 。


    5,ConfigureLogging

    读取配置文件中的Logging节点,配置日志系统。


    6,ConfigureServices

    //todo


    7,UseIIS

    使用IIS中间件。


    8,UseIISIntegration

    使用IISIntegration中间件。


    9,UseDefaultServiceProvider

    设置默认的依赖注入容器。

    宿主:IWebHost

    在ASP.Net Core中定义了IWebHost用来表示Web应用的宿主,并提供了一个默认实现WebHost。宿主的创建是通过调用IWebHostBuilder的Build()方法来完成的。看下源码:

    /// <summary>
            /// Builds the required services and an <see cref="IWebHost"/> which hosts a web application.
            /// </summary>
            public IWebHost Build()
            {
                if (_webHostBuilt)
                {
                    throw new InvalidOperationException(Resources.WebHostBuilder_SingleInstance);
                }
                _webHostBuilt = true;
    
                var hostingServices = BuildCommonServices(out var hostingStartupErrors);
                var applicationServices = hostingServices.Clone();
                var hostingServiceProvider = GetProviderFromFactory(hostingServices);
    
                if (!_options.SuppressStatusMessages)
                {
                    // Warn about deprecated environment variables
                    if (Environment.GetEnvironmentVariable("Hosting:Environment") != null)
                    {
                        Console.WriteLine("The environment variable 'Hosting:Environment' is obsolete and has been replaced with 'ASPNETCORE_ENVIRONMENT'");
                    }
    
                    if (Environment.GetEnvironmentVariable("ASPNET_ENV") != null)
                    {
                        Console.WriteLine("The environment variable 'ASPNET_ENV' is obsolete and has been replaced with 'ASPNETCORE_ENVIRONMENT'");
                    }
    
                    if (Environment.GetEnvironmentVariable("ASPNETCORE_SERVER.URLS") != null)
                    {
                        Console.WriteLine("The environment variable 'ASPNETCORE_SERVER.URLS' is obsolete and has been replaced with 'ASPNETCORE_URLS'");
                    }
                }
    
                AddApplicationServices(applicationServices, hostingServiceProvider);
    
                var host = new WebHost(
                    applicationServices,
                    hostingServiceProvider,
                    _options,
                    _config,
                    hostingStartupErrors);
                try
                {
                    host.Initialize();
    
                    var logger = host.Services.GetRequiredService<ILogger<WebHost>>();
    
                    // Warn about duplicate HostingStartupAssemblies
                    foreach (var assemblyName in _options.GetFinalHostingStartupAssemblies().GroupBy(a => a, StringComparer.OrdinalIgnoreCase).Where(g => g.Count() > 1))
                    {
                        logger.LogWarning($"The assembly {assemblyName} was specified multiple times. Hosting startup assemblies should only be specified once.");
                    }
    
                    return host;
                }
                catch
                {
                    // Dispose the host if there's a failure to initialize, this should clean up
                    // will dispose services that were constructed until the exception was thrown
                    host.Dispose();
                    throw;
                }
    
                IServiceProvider GetProviderFromFactory(IServiceCollection collection)
                {
                    var provider = collection.BuildServiceProvider();
                    var factory = provider.GetService<IServiceProviderFactory<IServiceCollection>>();
    
                    if (factory != null && !(factory is DefaultServiceProviderFactory))
                    {
                        using (provider)
                        {
                            return factory.CreateServiceProvider(factory.CreateBuilder(collection));
                        }
                    }
    
                    return provider;
                }
            }

    启动类:Startup

    每个ASP.NET Core程序都需要一个启动类,约定命名为:Startup。Startup用于配置服务和配置HTTP请求管道。

    namespace HelloNETCoreWebApi
    {
        public class Startup
        {
            public Startup(IConfiguration configuration)
            {
                Configuration = configuration;
            }
    
            public IConfiguration Configuration { get; }
    
            // This method gets called by the runtime. Use this method to add services to the container.
            public void ConfigureServices(IServiceCollection services)
            {
                services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
            }
    
            // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
            public void Configure(IApplicationBuilder app, IHostingEnvironment env)
            {
                if (env.IsDevelopment())
                {
                    app.UseDeveloperExceptionPage();
                }
                else
                {
                    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
                    app.UseHsts();
                }
    
                app.UseHttpsRedirection();
                app.UseMvc();
            }
        }
    }

    Startup必须包含Configure方法, 并选择包含ConfigureServices方法,这两个方法在应用程序启动时调用,该类还可以包含这些方法的特定环境的版本,并且ConfigureServices方法(如果存在)在Configure方法之前调用。

    Configure方法主要是配置ASP.NET Core的中间件,相当于我们在ASP.NET中所说的管道,ConfigureServices方法主要是配置依赖注入(DI)。

    原文地址:https://www.cnblogs.com/mcgrady/p/10243416.html