"跨平台"后的asp.net core是如何接收并处理请求的呢? 它的运行和处理机制和之前有什么不同?
本章从"宏观"到"微观"地看一下它的结构以及不同时期都干了些什么.
本章主要内容如下:
asp.net core 的运行机制: "宏观"的看一下http请求的处理流程.
asp.net core 的配置与运行: 2倍放大后的asp.net core application, kestrel服务器、启动与配置
asp.net core 的环境变量.
asp.net core 的运行机制
图1
asp.net core 的运行机制如上图所示, 现在做一下详细说明.
①web server: asp.net core提供两种服务器可用, 分别是kestrel和http.sys(core 1.x 中被命名为 weblistener),
a. kestrel是一个跨平台的web服务器;
b. http.sys只能用在windows系统中.
②internet: 当需要部署在internal network 中并需要 kestrel 中没有的功能(如 windows 身份验证)时,可以选择http.sys。
③iis、apache、nginx: kestrel 可以单独使用 ,也可以将其与反向代理服务器(如 iis、nginx 或 apache)结合使用。 请求经这些服务器进行初步处理后转发给kestrel(即图中虚线的可选流程).
大概的运行机制就是这样, 那么具体到asp.net core application是如何运行的呢? 我们将图1中asp.net core application这个红框框放大一下,看下一节.
asp.net core 的启动
看一下将图1的asp.net core application放大后的样子:
图2
④main方法, 程序的起点.
⑤创建并配置webhostbuilder: 首先调用createdefaultbuilder( 如图所示, 它是一系列配置的大综合,下文做详细介绍), 进行一系列配置之后, 调用 usestartup<t>(),
指定⑩startup为启动配置文件. 在startup中, 将进行两个比较重要的工作, ⑧服务的依赖注入和⑨配置管道, 后文将对这一部分详细的介绍.
⑥生成webhostbuilder并进行了一系列配置之后, 通过这个webhostbuilder来build出一个iwebhost.
⑦调用iwebhost的run方法使之开始运行.
asp.net core 应用程序本质上是控制台应用程序,所以它也是以一个我们熟悉的main方法作为程序的起点.
打开program.cs文件, 默认是如下代码
public class program
{
public static void main(string[] args)
{
buildwebhost(args).run();
}
public static iwebhost buildwebhost(string[] args) =>
webhost.createdefaultbuilder(args)
.usestartup<startup>()
.build();
}
定义了一个buildwebhost方法, 在main中调用它返回一个iwebhost, 并使这个iwebhost"run起来". 再看buildwebhost方法内部, 通过调用createdefaultbuilder
创建了一个iwebhostbuilder, 然后用这个builder来build出一个iwebhost.
简单来说就是 创建iwebhostbuilder=>builder=>build()=>iwebhost=>run().
webhostbuilder的一系列配置
系统离不开各种各样的配置, 比如常见的读取配置文件, 指定日志处理程序等, 我们详细的看一下.
createdefaultbuilder
createdefaultbuilder, 顾名思义, 它是一个默认配置 . 如图2所示, 它主要是调用了各种configurexxx和usexxx, 首先看一下它的源码
1 public static iwebhostbuilder createdefaultbuilder(string[] args) 2 { 3 var builder = new webhostbuilder() 4 .usekestrel() 5 .usecontentroot(directory.getcurrentdirectory()) 6 .configureappconfiguration((hostingcontext, config) => 7 { 8 var env = hostingcontext.hostingenvironment; 9 10 config.addjsonfile("appsettings.json", optional: true, reloadonchange: true) 11 .addjsonfile($"appsettings.{env.environmentname}.json", optional: true, reloadonchange: true); 12 13 if (env.isdevelopment()) 14 { 15 var appassembly = assembly.load(new assemblyname(env.applicationname)); 16 if (appassembly != null) 17 { 18 config.addusersecrets(appassembly, optional: true); 19 } 20 } 21 22 config.addenvironmentvariables(); 23 24 if (args != null) 25 { 26 config.addcommandline(args); 27 } 28 }) 29 .configurelogging((hostingcontext, logging) => 30 { 31 logging.addconfiguration(hostingcontext.configuration.getsection("logging")); 32 logging.addconsole(); 33 logging.adddebug(); 34 }) 35 .useiisintegration() 36 .usedefaultserviceprovider((context, options) => 37 { 38 options.validatescopes = context.hostingenvironment.isdevelopment(); 39 }); 40 41 return builder; 42 }
上面的源码中我们看到它这些configurexxx和usexxx的过程, 而在core 1.0版本中是没有createdefaultbuilder这个方法的,
系统默认是逐个调用这些configurexxx和usexxx的,在core 2.0中, 为了代码简洁和使用方便, 将这些常规情况下需要调用的方法放到了这个名为createdefaultbuilder的方法中.
一般情况下,调用createdefaultbuilder 执行其中的这些的默认配置足够用了。但既然这是默认配置, 我们就可以根据自身情况自定义.
因为这些配置都是对 webhostbuilder进行修改, 而修改后再次返回修改后的 webhostbuilder, 所以在createdefaultbuilder不符合现实需求的情况下可以通过如下的方法进行自定义.
1)不调用createdefaultbuilder, 将上面讲到的这些配置选择性的执行, 甚至可以添加、替换里面的某些配置, 如将usekestrel改为usehttpsys.
2)小幅改动, 即调用createdefaultbuilder之后再对其返回的webhostbuilder调用自定义的其他配置方法. 例如可以再次调用 configureappconfiguration,从而添加更多的配置源.
下面来介绍一下这些configurexxx和usexxx.
a. usekestrel
用于指定服务器使用 kestrel, 若使用httpsys, 需使用usehttpsys。
kestrel 是跨平台 asp.net core web 服务器,它基于 libuv(一个跨平台异步 i/o 库)。 kestrel 是 web 服务器,默认包括在 asp.net core 项目模板中。
kestrel 支持以下功能:
- https
- 用于启用 websocket 的不透明升级
- 用于获得 nginx 高性能的 unix 套接字.
默认情况下,asp.net core 项目模板使用的是 kestrel。
我们可以再次调用usekestrel来修改kestrel的配置, 例如限制请求正文的最大值
public static iwebhost buildwebhost(string[] args) =>
webhost.createdefaultbuilder(args)
.usestartup<startup>()
.usekestrel(options =>
{
options.limits.maxrequestbodysize = 10 * 1024;
})
.build();
b. usecontentroot
为应用程序指定根目录。需注意这和 staticfiles的根是不同的, 虽然默认情况下staticfiles的根是以contentroot为依据 ([contentroot]/wwwroot)。
c. configureappconfiguration
读取配置。如上代码会读取 appsettings.json 和 appsettings.{env.environmentname}.json , env.environmentname指的是环境, 例如development. 当在development环境的时候, 还会读取用户密钥。
这部分在学习系统配置的时候详细介绍.
d. configurelogging
配置日志处理程序,控制台和调试日志提供程序, 学习日志的时候再详讲.
e. useiisintegration
将应用程序配置为在 iis 中运行。上面已经讲过, 这里仍需要使用 usekestrel, 而iis 起到反向代理的作用,而 kestrel 仍用作主机。
如果应用程序没有使用 iis 作为反向代理,那么 useiisintegration 不会有任何效果。因此,即使应用程序在非 iis 方案中运行,也可以安全调用这种方法。
f.usedefaultserviceprovider
设置默认的依赖注入容器, 这部分在后面学习依赖注入的时候再详讲.
asp.net core 的环境
在 asp.net core 中,有个非常重要而且常用的东西叫环境变量, 它由 aspnetcore_environment 环境变量指定。
我们可以根据需要将此变量设置为任意值,但通常使用的是值 development、staging 和 production。它定义了当前应用程序的运行环境, 我们经常会根据这个变量来让应用采用不同的处理方式.
在上面的例子中, 就有这样的用法
if (env.isdevelopment()) { var appassembly = assembly.load(new assemblyname(env.applicationname)); if (appassembly != null) { config.addusersecrets(appassembly, optional: true); } }
_layout view 中
<environment include="development"> <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" /> <link rel="stylesheet" href="~/css/site.css" /> </environment>
因此,如果在run 之前将 aspnetcore_environment 变量设置为 development(或在 launchsettings.json 文件中设置此环境变量),
应用程序会在 development 模式下运行,而不是 production 模式(这是不设置任何变量时的默认模式)。
注意:在 windows 和 macos 上,环境变量和值不区分大小写。linux 环境变量和值区分大小写。
小结
通过上面的内容大概对asp.net core 2.0 的服务启动、配置与运行, 运行环境等做了大概的了解, 其中涉及的部分内容如读取配置、日志等, 将在后期单独介绍.
除了上述内容, asp.net core留给我们作为扩展的地方主要放在了startup文件中, 即图2中的⑩startup, 这里进行了两个比较重要的工作, ⑧服务的依赖注入和⑨配置管道,
下文我们将图2的⑩startup这个红框框放大一些, 看看这里都做了些什么.