先看下ASP.NET Core的啟動代碼,如下圖:通過以上代碼,我們可以初步得出以下結論:所有的ASP.NET Core程式本質上也是一個控制台程式,使用Program的Main方法作為程式的入口。控制台Main入口-->IWebHostBuilder-->IWebHost-->Run,發現本質上就... ...
先看下ASP.NET Core的啟動代碼,如下圖:
通過以上代碼,我們可以初步得出以下結論:
下麵結合源碼代詳細分析下。
宿主構造器: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)。