ASP.NET CORE 启动过程及源码解读

在这个特殊的春节,大家想必都在家出不了们,远看已经到了回城里上班的日子,但是因为一只蝙蝠的原因导致我们无法回到工作岗位,大家可能有的在家远程办公,有些在家躺着看书,有的是在家打游戏;在这个特殊无聊的日志,我果断从无聊的被窝中 开启了流量共享wifi 来进行.net core 3.1 源代码的解读和学习,并且把学习到的东西分享给大家。

疑问

刚刚接触ASP.NET CORE 项目的同学可能会有如下疑问:

  • ASP.NET CORE 项目的启动过程是怎么样的?
  • 为什么ASP.NET CORE项目可以在控制台中运行启动后变成了一个网站程序?

现在我这里使用.NETCORE 3.1 最新稳定发布版本来进行以上问题的解析,带大家解决以上问题的疑惑,学习完大家可以对ASP.NETCORE 项目会有一个不一样的理解和领悟.


启动过程

刚刚接触ASP.NET core 的同学们估计都会觉得和之前的ASP.NET 设计大不一样,代码风格也有很大的变化,以前的ASP.NET 是全家桶框架模式,里面包含了所有的实现,你用的到的用不到的都集成在里面;然而ASP.NET CORE 框架做了大的改变,以最小化抽象设计,通过扩展方法完成易用性扩展.

解读过源代码的同学们都可以发现大多api都是最小化单元抽象接口方式进行设计,其他复杂的方法api都是通过扩展方法进行扩展提供,这也是.NET Core 高效易扩展的一大优势原因.

对于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.NETCORE WEB 项目 步骤如下

文件-> 新建 -> 项目 -> 选择ASP.Net Core Web应用程序 -> 选择.NETCORE 3.1 框架 如图:

创建项目后我们从Program 类中可以看到以下代码:

public class Program
{
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)//开启一个默认的通用主机Host建造者
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    // 从前缀为“ASPNETCORE” 环境变量加载WEB主机配置
                    // 默认是Kestrel 设置为web 服务器并对其进行默认配置, 支持iis集成
                    //注册系统启动所使用的组件,比如配置的组件,容器的组件等
                    webBuilder.UseStartup<Startup>();
                });
}

查看以上代码可以发现 Main 方法中代码很简单 ,清晰可见

CreateHostBuilder(args) :方法创建了一个IHostBuilder 抽象对象,创建过程包含CreateDefaultBuilder(args) :开启创建一个默认的通用宿主机Host建造者,再通过ConfigureWebHostDefaults()方法配置开启默认的Kestrel 为默认的Web服务器并对其进行默认配置,并集成对iis的集成

Build() :负责创建IHost,看过源代码的同学可以发现Build的过程 会配置各种东西,本身通过管道模式进行了一系列的默认或者自定义的配置以及服务注册的构建(下面会详细讲解)

Run() :启动IHost

所以,ASP.NET Core应用的启动本质上是启动作为宿主的Host对象。

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

源代码详细图如下:

从上图中我们可以看出CreateDefaultBuilder()方法主要干了五件大事:
  • UseContentRoot:指定Web host使用的content root(内容根目录),比如Views。默认为当前应用程序根目录。
  • ConfigureHostConfiguration :启动时宿主机需要的环境变量等相关,支持命令行
  • ConfigureAppConfiguration:设置当前应用程序配置。主要是读取 appsettinggs.json 配置文件、开发环境中配置的UserSecrets、添加环境变量和命令行参数 。
  • ConfigureLogging:读取配置文件中的Logging节点,配置日志系统。
  • UseDefaultServiceProvider:设置默认的依赖注入容器。
从图中可以看出CreateDefaultBuilder 后调用了ConfigureWebHostDefaults 方法,该方法默认主要做了以下几个事情
  • UseStaticWebAssets:静态文件环境的配置启用
  • UseKestrel:开启Kestrel为默认的web 服务器.
  • ConfigureServices:服务中间件的注册,包含路由的中间件的注册
  • UseIIS:对iis 集成的支持
  • UseStartup:程序Startup 启动,该启动类中可以注册中间件、扩展第三方中间件,以及相关应用程序配置的处理等等操作
现在所有的配置都已经配置创建好了,接下来我们来看看Build 方法主要做了哪些不为人知的事情,先来看下源代码
/// <summary>
        /// Run the given actions to initialize the host. This can only be called once.
        /// </summary>
        /// <returns>An initialized <see cref="IHost"/></returns>
        public IHost Build()
        {
            if (_hostBuilt)
            {
                throw new InvalidOperationException("Build can only be called once.");
            }
            _hostBuilt = true;

            BuildHostConfiguration();
            CreateHostingEnvironment();
            CreateHostBuilderContext();
            BuildAppConfiguration();
            CreateServiceProvider();

            return _appServices.GetRequiredService<IHost>();
        }

从代码中可以发现有一个_hostBuilt 的变量,细心的同学可以发现该变量主要是用于控制是否build 过,所以这里可以大胆猜测只能build 一次该Host;现在看下源代码解析图:

经过查看源代码得到的执行结构如上,因此我把代码改造成如下结构。

public class Program
{
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)//开启一个默认的通用主机Host建造者
                .ConfigureAppConfiguration(config => {
                    //注册应用程序内所使用的配置文件,比如数据库链接等等
                    Console.WriteLine("ConfigureAppConfiguration");
                })
                .ConfigureServices(service =>
                {
                    //注册服务中间件等操作
                    Console.WriteLine("ConfigureServices");
                })
                .ConfigureHostConfiguration(builder => {
                    //启动时需要的组件配置等,比如监听的端口 url地址等
                   Console.WriteLine("ConfigureHostCOnfiguration");
                })
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });
}

Startup 代码如下:

public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
            Console.WriteLine("Startup ");
        }

        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)
        {
            Console.WriteLine("ConfigureServices");
            services.AddControllersWithViews();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            Console.WriteLine("Configure");
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
                // 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.UseStaticFiles();

            app.UseRouting();

            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller=Home}/{action=Index}/{id?}");
            });
        }
    }
}

通过执行发现执行代码顺序正如我们源代码的执行顺序一致,执行顺序如下图:

为何通过控制台命令运行后自动启动了一个网站程序?

以前ASP.NET web项目是需要搭建在iis 中托管运行,但是ASP.NETCORE 项目可以直接通过命令行进行托管运行,运行后可以直接浏览器打开,你们有没有考虑过为什么?,细心的同学查看项目属性也会发现项目的输出类型也是控制台项目,如图:

查看这图,有没有发现很神奇,为什么输出类型竟然可以通过控制台命令行进行启动项目呢?

在上面的源代码分析过程中可以发现启动时会启动一个Kestrel 服务器(ConfigureWebHostDefaults方法中会调用UseKestrel),所以命令后启动一个控制台应用程序后相当于启动了一台web服务器;下面简要的概括下Kestrel 服务器的优势:

  • Kestrel:Kestrel 是个精简高效的 HttpServer,以包形式提供,自身不能单独运行。

内部封装了对 libuv 的调用,作为I/O底层,屏蔽各系统底层实现差异;有了Kestrel才能真正的实现跨平台.
好了,想必同学们到这里已经对上面 两个疑惑有了清晰的答案了。这里我抛出一个疑问,看了上面的代码解读,大家有没有发现ASP.NET CORE 和ASP.NET 有了很大的不同,这是什么样的设计改进呢?敬请期待下期我们一起来学习ASP.NET CORE 的牛逼的管道模型.

(0)

相关推荐

  • .NET 6 Preview 3 中 ASP.NET Core 的更新和改进

    原文:bit.ly/2Qb56NP作者:Daniel Roth译者:精致码农-王亮.NET 6 预览版 3 现已推出,其中包括许多对新的 ASP.NET Core 改进.以下是本次预览版的新内容:更小 ...

  • Windows平台部署Asp.Net Core应用

    一. 简介 Asp.Net Core 部署方式有两种:依赖框架和独立部署. 1. 框架依赖的部署: 顾名思义,依赖框架的部署 (FDD) 依赖目标系统上存在共享系统级版本的 .NET Core. 由于 ...

  • 如何在 ASP.Net Core 中使用 HTTP.sys WebServer ?

    dotNET跨平台 今天 以下文章来源于码农读书 ,作者码农读书 ASP.Net Core 是一个开源的,跨平台的,轻量级模块化框架,可用它来构建高性能的Web程序,大家都知道 Kestrel 是 A ...

  • Asp.net Core Kestrel 免费实现https

    0.概述 先了解下https是个啥: https://www.bilibili.com/video/BV1j7411H7vV so!只要给我们的web服务器配置一个证书就行了,证书可以买,也可以用免费 ...

  • 10.ASP.NET Core launchSettings.json file

    这篇文章,我将带领大家学习ASP.NET Core中的launchSettings.json文件.为了学习它,我们打开之前建的空白模板的ASP.NET Core项目. 从上面的图片中你可以看到,我们项 ...

  • 如何在 ASP.Net Core 中使用 Serilog

    记录日志的一个作用就是方便对应用程序进行跟踪和排错调查,在实际应用上都是引入 日志框架,但如果你的 日志文件 包含非结构化的数据,那么查询起来将是一个噩梦,所以需要在记录日志的时候采用结构化方式. 将 ...

  • Hosting in .NET Core

    Johnny Qian dotNET跨平台 今天在.NET Core中,Host负责应用程序的启动和生命周期管理.除此之外,在Host中还可以设置日志(Logging).配置(Configuratio ...

  • 9.ASP.NET Core OutOfProcess Hosting

    这篇文章中,我将详细介绍ASP.NET Core OutOfProcess Hosting模型.强烈推荐你去看看我之前写的ASP.NET Core InProcess以及ASP.NET Core中的 ...

  • ASP.NET Core 5-Kestrel源码解读

    上节讲到了kestrel服务器的配置及使用,相信很多同学已经对kestrel服务器有了初步的了解,那么有的同学可能会想更加深入的了解一下Kestrel服务器的是怎么实现监听和接收http请求的,今天我 ...

  • 股价启动在即选股源码

    条件选股:股价启动在即[日线]成功率测试 测试股票数:4470 共发出信号:124353成功信号:54135失败信号:68721未完成信号:1497 信号发出率:97.05%平均成功率:44.06%成 ...

  • 捉牛股妖股黑马启动选股公式源码及成功率

    条件选股:捉牛股妖股黑马启动[日线]成功率测试 测试股票数:4473 共发出信号:29126成功信号:16902失败信号:12064未完成信号:160 信号发出率:92.40%平均成功率:58.35% ...

  • 牛浮面妖股启动选股公式源码

    条件选股:牛浮面妖股启动[日线]成功率测试 测试股票数:4477 共发出信号:137443成功信号:79227失败信号:57657未完成信号:559 信号发出率:93.19%平均成功率:57.88%成 ...

  • 主升浪启动选股公式源码及成功率

    条件选股:主升浪启动[日线]成功率测试 测试股票数:4481 共发出信号:13523成功信号:5556失败信号:7779未完成信号:188 信号发出率:78.22%平均成功率:41.66%成功率达到5 ...

  • 神仙操盘主图启动选股公式源码及成功率

    条件选股:月神仙操盘主图启动[日线]成功率测试 测试股票数:4483 共发出信号:121121成功信号:60157失败信号:60286未完成信号:678 信号发出率:96.56%平均成功率:49.95 ...

  • 【妖股启动】指标源码免费分享(源码)

    吾爱指标提醒您: 炒股技术千万条,稳定盈利第一条. 追涨杀跌不可为,否则只剩两行泪. [精品指标分享] 指标源码(选股预警+幅图)

  • 换手率异动变色牛股启动选股公式源码及成功率

    条件选股:换手率异动牛股启动[日线]成功率测试 测试股票数:4491 共发出信号:108443成功信号:50316失败信号:57321未完成信号:806 信号发出率:87.91%平均成功率:46.75 ...

  • 看色操作启动选股公式源码及成功率

    条件选股:看色操作启动[日线]成功率测试 测试股票数:4516 共发出信号:124767成功信号:54631失败信号:69517未完成信号:619 信号发出率:96.68%平均成功率:44.00%成功 ...