• 一张图理清ASP.NET Core启动流程


    ASP.NET Core知多少系列:总体介绍及目录

    1. 引言

    对于ASP.NET Core应用程序来说,我们要记住非常重要的一点是:其本质上是一个独立的控制台应用,它并不是必需在IIS内部托管且并不需要IIS来启动运行(而这正是ASP.NET Core跨平台的基石)。ASP.NET Core应用程序拥有一个内置的Self-Hosted(自托管)Web Server(Web服务器),用来处理外部请求。

    不管是托管还是自托管,都离不开Host(宿主)。在ASP.NET Core应用中通过配置并启动一个Host来完成应用程序的启动和其生命周期的管理(如下图所示)。而Host的主要的职责就是Web Server的配置和Pilpeline(请求处理管道)的构建。
    ASP.NET Core总体启动流程

    这张图描述了一个总体的启动流程,从上图中我们知道ASP.NET Core应用程序的启动主要包含三个步骤:

    1. CreateDefaultBuilder():创建IWebHostBuilder
    2. Build():IWebHostBuilder负责创建IWebHost
    3. Run():启动IWebHost

    所以,ASP.NET Core应用的启动本质上是启动作为宿主的WebHost对象。
    其主要涉及到两个关键对象IWebHostBuilderIWebHost,它们的内部实现是ASP.NET Core应用的核心所在。下面我们就结合源码并梳理调用堆栈来一探究竟!

    2. 宿主构造器:IWebHostBuilder

    在启动IWebHost宿主之前,我们需要完成对IWebHost的创建和配置。而这一项工作需要借助IWebHostBuilder对象来完成的,ASP.NET Core中提供了默认实现WebHostBuilder。而WebHostBuilder是由WebHost的同名工具类(Microsoft.AspNetCore命名空间下)中的CreateDefaultBuilder方法创建的。

    CreateDefaultBuilder()调用堆栈

    从上图中我们可以看出CreateDefaultBuilder()方法主要干了六件大事:

    1. UseKestrel:使用Kestrel作为Web server。
    2. UseContentRoot:指定Web host使用的content root(内容根目录),比如Views。默认为当前应用程序根目录。
    3. ConfigureAppConfiguration:设置当前应用程序配置。主要是读取 appsettinggs.json 配置文件、开发环境中配置的UserSecrets、添加环境变量和命令行参数 。
    4. ConfigureLogging:读取配置文件中的Logging节点,配置日志系统。
    5. UseIISIntegration:使用IISIntegration 中间件。
    6. UseDefaultServiceProvider:设置默认的依赖注入容器。

    创建完毕WebHostBuilder后,通过调用UseStartup()来指定启动类,来为后续服务的注册及中间件的注册提供入口。

    3. 宿主:IWebHost

    在ASP.Net Core中定义了IWebHost用来表示Web应用的宿主,并提供了一个默认实现WebHost。宿主的创建是通过调用IWebHostBuilderBuild()方法来完成的。那该方法主要做了哪些事情呢,我们来看下面这张【ASP.NET Core启动流程调用堆栈】中的黄色边框部分:

    ASP.NET Core启动流程调用堆栈

    其核心主要在于WebHost的创建,又可以划分为三个部分:

    1. 构建依赖注入容器,初始通用服务的注册:BuildCommonService();
    2. 实例化WebHost:var host = new WebHost(...);
    3. 初始化WebHost,也就是构建由中间件组成的请求处理管道:host.Initialize();

    3.1. 注册初始通用服务

    BuildBuildCommonService方法主要做了两件事:

    1. 查找HostingStartupAttribute特性以应用其他程序集中的启动配置
    2. 注册通用服务
    3. 若配置了启动程序集,则发现并以IStartup类型注入到IOC容器中

    3.2. 创建IWebHost

    public IWebHost Build()
    {
        //省略部分代码
    
        var host = new WebHost(
            applicationServices,
            hostingServiceProvider,
            _options,
            _config,
            hostingStartupErrors);
        }
        
        host.Initialize();
    
        return host;
    }
    

    3.3. 构建请求处理管道

    请求管道的构建,主要是中间件之间的衔接处理。

    而请求处理管道的构建,又包含三个主要部分:

    1. 注册Startup中绑定的服务;
    2. 配置IServer;
    3. 构建管道

    请求管道的构建主要是借助于IApplicationBuilder,相关类图如下:
    请求管道的构建

    4. 启动WebHost

    WebHost的启动主要分为两步:

    1. 再次确认请求管道正确创建
    2. 启动Server以监听请求
    3. 启动 HostedService

    启动WebHost调用堆栈

    4.1. 确认请求管道的创建

    从图中可以看出,第一步调用Initialize()方法主要是取保请求管道的正确创建。其内部主要是对BuildApplication()方法的调用,与我们上面所讲WebHost的构建环节具有相同的调用堆栈。而最终返回的正是由中间件衔接而成的RequestDelegate类型代表的请求管道。

    4.2. 启动Server

    我们先来看下类图:

    IServer类图

    从类图中我们可以看出IServer接口主要定义了一个只读的特性集合属性、一个启动和停止的方法声明。在创建宿主构造器IWebHostBuilder时我们通过调用UseKestrel()方法指定了使用KestrelServer作为默认的IServer实现。其方法申明中接收了一个IHttpApplication<TContext> application的参数,从命名来看,它代表一个Http应用程序,我们来看下具体的接口定义:

    IHttpApplication类图

    其主要定义了三个方法,第一个方法用来创建请求上下文;第二个方法用来处理请求;第三个方法用来释放上下文。而至于请求上下文,是用来携带请求和返回响应的核心参数,其贯穿与整个请求处理管道之中。ASP.NET Core中提供了默认的实现HostingApplication,其构造函数接收一个RequestDelegate _application(也就是链接中间件形成的处理管道)用来处理请求。

    var httpContextFactory = _applicationServices.GetRequiredService<IHttpContextFactory>();
    var hostingApp = new HostingApplication(_application, _logger, diagnosticSource, httpContextFactory);
    

    4.3. 启动IHostedService

    IHostedService接口用来定义后台任务,通过实现该接口并注册到Ioc容器中,它会随着ASP.NET Core 程序启动而启动,终止而终止。

    5. 总结

    结合源码,通过对ASP.NET Core运行调用堆栈的梳理,其启动流程的总体脉络一目了然,并且了解到主要的几个关键对象:

    1. 负责创建IWebHost的宿主构造器IWebHostBuilder
    2. 代表宿主的IWebHost接口
    3. 用于构建请求管道的IApplicationBuilder
    4. 中间件衔接而成的RequestDelegate
    5. 代表Web Server的IServer接口
    6. 贯穿请求处理管道的请求上下文HttpContext
    7. 可以用来注册后台服务的IHostedService接口

    本文经「原本」原创认证,作者圣杰,访问yuanben.io查询【E5OW396N】获取授权信息。

  • 相关阅读:
    sentinel使用内置规则检测威胁——自定义规则是使用的KQL
    在Azure Sentinel中使用威胁情报——可以自己订阅,自己创建一条indicator来使用基于情报的检测
    sm2国密算法的纯c语言版本,使用于单片机平台(静态内存分配)
    JDK-8180048 : Interned string and symbol table leak memory during parallel unlinking
    CMS垃圾收集器小实验之CMSInitiatingOccupancyFraction参数
    记spring boot线上项目内存优化
    springboot 配置log4j2日志,并输出到文件
    SpringBoot 日志管理之自定义Appender
    Linux 上 定时备份postgresql 数据库的方法
    linux下执行sh脚本,提示Command not found解决办法
  • 原文地址:https://www.cnblogs.com/sheng-jie/p/7640163.html
Copyright © 2020-2023  润新知