ASP.NET Core基础1:应用启动流程
先看下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)。
推荐阅读