服务是如何加载并运行的, Kestrel、配置与环境

"跨平台"后的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: 首先调用Create­DefaultBuilder( 如图所示, 它是一系列配置的大综合,下文做详细介绍), 进行一系列配置之后, 调用 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的一系列配置

系统离不开各种各样的配置, 比如常见的读取配置文件, 指定日志处理程序等, 我们详细的看一下.

Create­DefaultBuilder

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的方法中.

一般情况下,调用Create­DefaultBuilder 执行其中的这些的默认配置足够用了。但既然这是默认配置,  我们就可以根据自身情况自定义.

因为这些配置都是对 WebHostBuilder进行修改, 而修改后再次返回修改后的 WebHostBuilder, 所以在Create­DefaultBuilder不符合现实需求的情况下可以通过如下的方法进行自定义.

1)不调用Create­DefaultBuilder, 将上面讲到的这些配置选择性的执行, 甚至可以添加、替换里面的某些配置, 如将UseKestrel改为UseHttpSys.

2)小幅改动, 即调用Create­DefaultBuilder之后再对其返回的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这个红框框放大一些, 看看这里都做了些什么.

服务是如何加载并运行的, Kestrel、配置与环境的更多相关文章

  1. ASP.NET Core 2.0 : 五.服务是如何加载并运行的, Kestrel、配置与环境

    "跨平台"后的ASP.Net Core是如何接收并处理请求的呢? 它的运行和处理机制和之前有什么不同? 本章从"宏观"到"微观"地看一下它的 ...

  2. C#如何加载程序运行目录外的程序集

    我们的应用程序部署的时候,目录结构一般不会只有运行程序的目录这一个,我们可能在运行目录下建子目录,也可能使用System32目录,也可能使用其它第三方的程序集..Net程序集 首先会在GAC中搜索相应 ...

  3. 未能加载文件或程序集“BLL”或它的某一个依赖项。生成此程序集的运行时比当前加载的运行时新,无法加载此程序集。

    今天使用VS2012创建项目的时候,考虑到项目中代码的重用性以及清晰简洁性,搭建了一个三层架构,但是在项目运行的时候,总是报错: “未能加载文件或程序集“BLL”或它的某一个依赖项.生成此程序集的运行 ...

  4. Linux进程启动过程分析do_execve(可执行程序的加载和运行)---Linux进程的管理与调度(十一)

    execve系统调用 execve系统调用 我们前面提到了, fork, vfork等复制出来的进程是父进程的一个副本, 那么如何我们想加载新的程序, 可以通过execve来加载和启动新的程序. x8 ...

  5. (转)C#如何加载程序运行目录外的程序集

    https://www.cnblogs.com/guanglin/p/3200989.html 我们的应用程序部署的时候,目录结构一般不会只有运行程序的目录这一个,我们可能在运行目录下建子目录,也可能 ...

  6. 【Hight Performance Javascript】——脚本加载和运行

    脚本加载和运行 当浏览器遇到一个<script>标签时,无法预知javascript是否在<p>标签中添加内容.因此,浏览器停下来,运行javascript代码,然后继续解析. ...

  7. 【记录】尝试用QEMU模拟ARM开发板去加载并运行Uboot,kernel,rootfs【转】

    转自:https://www.crifan.com/try_use_qemu_emulate_arm_board_to_load_and_run_uboot_kernel_rootfs/ [背景] 手 ...

  8. [转] Linux下程序的加载、运行和终止流程

    TAG: linux, main, _start DATE: 2013-08-08 原文地址: http://blog.csdn.net/tigerscorpio/article/details/62 ...

  9. 解剖Nginx·模块开发篇(4)模块开发中的命名规则和模块加载与运行流程

    1 命名规则 1.1 基本变量 基本变量有三个: ngx_module_t 类型的 ngx_http_foo_bar_module: ngx_command_t 类型的数组 ngx_http_foo_ ...

随机推荐

  1. C++ 精确计时类

    http://hi.baidu.com/ronyo/blog/item/ee7e71cf7d46c338f8dc61ad .html    在一些程序中经常要统计一个算法/函数花费的时间,每次都重新写 ...

  2. ES 搜索结果expalain 可以类似数据库性能调优来看排序算法的选择

    When we run a simple term query with explain set to true (see Understanding the Score), you will see ...

  3. JavaMail API的应用

    JavaMail API 是一个用于阅读.编写和发送电子消息的可选包(标准扩展),用来创建邮件用户代理(Mail User Agent,MUA)类型程序. JavaMail API 需要 JavaBe ...

  4. 【C++基础】浅拷贝和深拷贝

    简单理解: 对于一块内存,浅拷贝只是增加了一个指针,这样两个变量都指向这块内存,二深拷贝则是先开辟一块同等大小的新内存区,将待拷贝内存的内容复制过来,再赋予一个指向新内存的指针.区别在于:浅拷贝会造成 ...

  5. POJ2387(最短路入门)

    Til the Cows Come Home Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 38556   Accepted ...

  6. CentOS下编写shell脚本来监控MySQL主从复制的教程

    这篇文章主要介绍了在CentOS系统下编写shell脚本来监控主从复制的教程,文中举了两个发现故障后再次执行复制命令的例子,需要的朋友可以参考下 目的:定时监控MySQL主从数据库是否同步,如果不同步 ...

  7. Behave + Selenium(Python) 四

    来自T先生 今天我们开始讲讲behave的厉害的地方. Tag文件的使用 在behave里面,如何来控制哪些case需要run,哪些case不需要run,这个时候就用Tag来控制.好了,接下来我用Ta ...

  8. GET请求中的乱码原理解析和解决方案

    2. 乱码问题解决 基础知识 1)浏览器会在中文的UTF-8后加上上%得到URL编码   例如: %e8%b4%b9%e7%94%a8%e6%8a%a5%e9%94%80 2)以get的请求发送到to ...

  9. Entity Framework之领域驱动设计实践

    http://www.cnblogs.com/daxnet/archive/2010/11/02/1867392.html

  10. oracle处理重复数据

    oracle查找重复记录 SELECT *FROM t_info aWHERE ((SELECT COUNT(*)          FROM t_info          WHERE Title ...