zoukankan      html  css  js  c++  java
  • asp.net core 3.1 入口:Program.cs中的Main函数

    本文分析Program.cs 中Main()函数中代码的运行顺序分析asp.net core程序的启动,重点不是剖析源码,而是理清程序开始时执行的顺序。到底用了哪些实例,哪些法方。

    asp.net core 3.1 的程序入口在项目Program.cs文件里,如下。

    ususing System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Hosting;
    using Microsoft.Extensions.Configuration;
    using Microsoft.Extensions.Hosting;
    using Microsoft.Extensions.Logging;
    
    namespace WebDemo
    {
        public class Program
        {
            public static void Main(string[] args)
            {
                CreateHostBuilder(args).Build().Run();
            }
    
            public static IHostBuilder CreateHostBuilder(string[] args) =>
                Host.CreateDefaultBuilder(args)
                    .ConfigureWebHostDefaults(webBuilder =>
                    {
                        webBuilder.UseStartup<Startup>();
                    });
        }
    }

    1. Program类

    program类是定义在项目根目录Program.cs文件中,所有.net core程序的入口,包括asp.net core 程序。这很有意思,就有点类似控制端程序。相比之前的web项目没有任何程序入口只有web.config、global这类配置文件和全局文件这种没有程序入口web项目,我觉得这类更容易理解asp.net core是怎么工作的。

    在asp.net core 3.1中 的Program类里,定义了2个方法:Main() 和CreateHostBuilder()

    2. 主程序入口Program.Main()方法

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

    Main() 方法是整个项目的入口方法,就如同C系列语言,所有的程序入口都是。这里main()只有一行代码,但是实际上执行了三个函数C:

      1 IHostBuilder builder= CreateHostBuilder(args);
      2 IHost host=builder.Build();
      3 host.Run();

    第一行,是定义在Program类的CreateHostBuilder 它主要产生一个IhostBuilder实例builder。

    第二行,通过builder.Build()法方产生一个Ihost实例 host。

    第三含,通过host.Run()方法,开始运行web项目,这时候就可以响应各种请求了。

    而这个过程里最繁琐的就是创建builder,本文重点篇幅就是在这里。

    3. 创建并配置主机Builder:Program.CreateHostBuilder(args)法方

    分解CreateHostBuilder(args) 的定义

    此法方通过lamada表达式定义在Pogram类中。因为它就执行了一句化,所以可以用这种简便的方式定义(关于匿名函数、lamada、内置委托可以参考我之前的文章C# 匿名方法(函数) 匿名委托 内置泛型委托 lamada1)。为了方便阅读按照上面刨析Main()法方,所以它实际的定义如下:

      1         public static IHostBuilder CreateHostBuilder(string[] args)
      2         {
      3             IHostBuilder builder = Host.CreateDefaultBuilder(args);
      4             Action < IWebHostBuilder > configAction = delegate(IWebHostBuilder webBuilder)
      5             {
      6                 webBuilder.UseStartup<Startup>();
      7             };
      8             builder=builder.ConfigureWebHostDefaults(configAction);
      9             return builder;
     10         }

    3.1. builder诞生 :生成IHostBuilder

    将从Host.CreateHostBuilder()法方分析入手

    CreateHostBuilder()法方的第一行代码是调用Host.CreateDefaultBuilder(args)法方,来创建IBuilder 对象实例。

    IHostBuilder builder = Host.CreateDefaultBuilder(args);

    IHostBuilder是一个非常重要的实例,有了这个实例才可以继续后续的加载更多的配置操作。通过IHostBuilder.Build()生产IHost实例。最终通过IHost.Run()运行项目。

    3.1.1 Host类——用于产生初始的builder静态类

    Host类是定义在Microsoft.Extensions.Hosting命名空间(Program.cs中引用了该命名公开)下的静态类.在Program.cs里引入。

    声明如下:

      1 using Microsoft.Extensions.Hosting;
      2 
      3 namespace Microsoft.Extensions.Hosting
      4 {
      5     public static class Host
      6     {
      7 	    public static IHostBuilder CreateDefaultBuilder();
      8         public static IHostBuilder CreateDefaultBuilder(string[] args);
      9     }
     10 }

    Host静态类就一个法方就是CreateDefaultBuilder() 。合计2个重载声明:一个带参数,一个不带参数。参考源码(.NET Core 3.0之深入源码理解Host(一)2)不带参数的重载实际在是将null作为参数调用带参数形式,如下:

      1 public static IHostBuilder CreateDefaultBuilder() =>CreateDefaultBuilder(args: null);
    
    3.1.2 Host.CreateDefaultBuilder(args)方法
    官方说明是用预先配置的默认值初始化一个Microsoft.Extensions.Hosting.HostBuilder实例(Initializes a new instance of the Microsoft.Extensions.Hosting.HostBuilder class with pre-configured defaults,详细见参考官方文档3)。
    相关操作有:设置根目录ContentRootPath ;给Host.IConfiguration 加载:环境变量EnvironmentName,命令行参数args,配置文件IConfiguration.[EnvironmentName] json;还有加载日志模块等等。
    详细见参考文档2、3,其中.NET Core 3.0之深入源码理解Host(一),作者从源码角度剖析了此法方,官方文档Host.CreateDefaultBuilder 方法官方说明了法方操作那些内容。

    3.2. IHostBuilder转变成IWebHostBuilder

    继续对Host.CreateHostBuilder()法方分析,在3.1建立了IHostBuilder实例后,将通过builder.ConfigureWebHostDefaults(Action <IWebHostBuilder >)方法将IHostBuilder实例转变为一个web主机性质的webbuilder(IWebHostBuilder)

    IHoustBuilder.ConfigureWebHostDefaults(Action <IWebHostBuilder>)方法定义在Microsoft.Extensions.Hosting.GenericHostBuilderExtensions静态类中(GenericHostBuilderExtensions.cs),此静态类就定义这一个静态方法。

    3.2.1. ConfigureWebHostDefaults()参数

    此处参数configure是一个内置委托Action <IWebHostBuilder>,这个委托的定义就执行一行代码:
    webBuilder.UseStartup<Startup>();

    3.2.2. ConfigureWebHostDefaults()方法定义

    其实ConfigureWebHostDefaults(Action <IWebHostBuilder >)方法是一个IHostBuilder的扩展方法(所以之前的写法并不准确,缺少了this builder参数,之前省略了)。
    为了方便阅读法,用3.中的方式码剖析如下:
      1  	     public static IHostBuilder ConfigureWebHostDefaults(this IHostBuilder builder, Action<IWebHostBuilder> configure)
      2         {
      3             Action<IWebHostBuilder> webconfigure = delegate(IWebHostBuilder webHostBuilder)
      4             {
      5                 WebHost.ConfigureWebDefaults(webHostBuilder);
      6                 configure(webHostBuilder);
      7             };
      8             return builder.ConfigureWebHost(webconfigure);
      9         }
    其实就调取了IHostBuilder的另一个扩展类ConfigureWebHost(Action<IWebHostBuilder>)(此扩展法方定义在Microsoft.Extensions.Hosting.GenericHostWebHostBuilderExtensions静态类中)。

    3.2.2.1 把IHostBuilder转变为IWebHostBuilder: builder.ConfigureWebHost(webconfigure)法方

    3.2.2.1.1 Action<IWebHostBuilder> webconfigure参数
    内置委托,在这里对委托进行了定义,主要两行代码:
    配置IWebHostBuilder的默认web设置。
    WebHost.ConfigureWebDefaults(webHostBuilder);
    在core2.1中该方法是在CreateHostBuilder()中WebHost.CreateDefaultBuilder(arg)中调用,core3.1,改为Host.ConfigureDefualts(arg)后,通过委托在ConfigureWebHost中调用。因为此方法在委托里调用,在下面章节降到委托执行的时候再详细说明。
    调用参数传入的委托
    configure(webHostBuilder);
     就是3.2.1中的
    webBuilder.UseStartup<Startup>();
    具体在下面章节讲解委托执行时在详细说明。
    3.2.2.1.2 builder.ConfigureWebHost(webconfigure)法方定义
    定义在Microsoft.Extensions.Hosting.GenericHostWebHostBuilderExtensions(GenericHostWebHostBuilderExtensions.cs) 
      1 using System;
      2 using Microsoft.AspNetCore.Hosting;
      3 using Microsoft.AspNetCore.Hosting.Internal;
      4 
      5 namespace Microsoft.Extensions.Hosting
      6 {
      7     public static class GenericHostWebHostBuilderExtensions
      8     {
      9         public static IHostBuilder ConfigureWebHost(this IHostBuilder builder, Action<IWebHostBuilder> configure)
     10         {
     11             var webhostBuilder = new GenericWebHostBuilder(builder);
     12             configure(webhostBuilder);
     13             return builder;
     14         }
     15     }
     16 }
    Microsoft.AspNetCore.Hosting.Internal.GenericWebHostBuilder
    在asp.net core 2.1 里IWebHostBuilder 在asp.net core 3.1里是怎么把泛型IHostBuilder生产webhost的builder的了,终于扒到它了。  
    通过Microsoft.AspNetCore.Hosting.Internal.GenericWebHostBuilder类实例。GenericWebHostBuilder是一个内部类。这个类网上资源极少,甚至在官方文档里找不到说明,但可以参考其源码GenericWebHostBuilder.cs源代码。此类声明和其构造函数声明如下:
    internal class GenericWebHostBuilder : IWebHostBuilder, ISupportsStartup, ISupportsUseDefaultServiceProvider
    {
         public GenericWebHostBuilder(IHostBuilder builder);
    }
    此类非常重要,它是Asp.net core 3.1 项目中IHostBuilder转变成IWebHostBuilder的基石或者源头 一个IHostBuilder实例最早就是通过此类构造函数实例化后变成了2.1里的IWebHostBuilder。实际干的就是注入了一些web有关的服务,详细建议查看源码(参考文档4
    3.2.2.2 给IWebHostBuilder配置Web相关参数委托参数:终于执行委托了
    configure(webhostBuilder);
    在传入了那么多层委托后,终于我们扒到底了,在实现了IHostBuilder转变为IWebHostBuilder后,所有config有关的委托终于得以执行
      1 //在 builder.ConfigureWebHostDefaults()(-->在program.GreateHostBuilder()中)
      2 //和下一句代码一同作为委托参数传入builder.ConfigureWebHost()
      3 WebHost.ConfigureWebDefaults(webHostBuilder);
      4 //Program.CreateHostBuilder()里的作为委托参数传入builder.ConfigureWebHostDefaults()
      5 //再经过builder.ConfigureWebHostDefaults()合上一句一同作为委托传入builder.ConfigureWebHost()
      6 webBuilder.UseStartup<Startup>();
    
    3.2.2.2.1 WebHost.ConfigureWebDefualts(IWebHostBuilder)方法:
    此方法在Asp.net core 2.1中 是WebHost.CreateDefaultBuilder(args) 里最后调用的方法,而在Asp.net core 3.1中,把IWebHostBuilder该为泛型IHostBuilder后,在执行IHostBuilder.ConfigureWebHost()时回调委托执行。此方法作用类似与Host.CreateDefaultBuilder(args),使用预配置配置一些关于Web方式的参数。主要是注入一些web相关的服务,配置主机地址等。此方法没有官方文档说明,建议直接查看源码WebHost.cs源代码(参考文档5)。
    3.2.2.2.2 webBuilder.UseStartup<Startup>()法方:
    UseStartup()是webbuilder的扩展发放,定义在Microsoft.AspNetCore.Hosting.WebHostBuilderExtensions静态类中(WebHostBuilderExtensions.cs),此方法申明如下
    public static IWebHostBuilder UseStartup(this IWebHostBuilder hostBuilder, Type startupType)

    从方法名就可以看出是使用Startup类,这个方法主要使用反射技术,反射Startup类,响应startup类中的配置的信息

    3.3. 最后梳理一下builder核心的代码

    1.IHostBuilder builder = Host.CreateDefaultBuilder(args);
    创建一个基础builder(读取app.json)
    2.IWebHostBuilder webHostBuilder= new GenericWebHostBuilder(builder);
    转换为webbuilder
    3.WebHost.ConfigureWebDefaults(webHostBuilder);
    给webbuilder使用预先的默认值配置
    4.webBuilder.UseStartup<Startup>();
    读取startup类配置信息

    4.总结

    aps.net core 3.1的程序启动代码分析下来。基本3个概念创建builder ,通过builder生成host ,最后使用host执行起来。其中builder及builder配置 ,host主机都是重要的概念。core 3.1 和 core2.1的区别,就是把IWebHostBuilder上再抽象一个IHostBuilder,可以是core 3.1的代码更加的灵活,以后的服务可以不单单是web服务。
    另外asp.net core 的builder 配置中可以看到很多非常依赖,控制反转技术也就是注入依赖,好处就是想要什么服务就注册什么服务,更加灵活。
    如果想深入学习,建议参考如下文章:

    1. .NET Core 3.0之深入源码理解Host(一)
    2. .NET Core 3.0之深入源码理解Host(二)
      作者的这个2个文章从源码角度简介了Ihostbuilder的相关知识剖析深度更深
    3. 官方文档:.NET 通用主机 讲解IHostBuilder相关知识
    4. 官方文档:ASP.NET Core 中的应用启动 介绍startup类相关知识


    参考文档:
    1. C# 匿名方法(函数) 匿名委托 内置泛型委托 lamada 作者:edzjx
    2. .NET Core 3.0之深入源码理解Host(一) 作者:艾心
    3. 官方文档Host.CreateDefaultBuilder 方法 作者:Micrsoft官方文档
    4. GenericWebHostBuilder.cs源代码 作者:Asp.net@github 
    5. WebHost.cs源代码 作者:Asp.net@github 
    6. .NET Core 3.0之深入源码理解Host(二) 作者:艾心
    7. 官方文档:.NET 通用主机 作者:Micrsoft官方文档
    8. 官方文档:ASP.NET Core 中的应用启动 作者:Micrsoft官方文档

  • 相关阅读:
    Apache基本设置
    主流无线传输技术GPRS与CDMA之对比
    光波分复用系统(WDM)技术要求
    IPv6报头结构以及与IPv4的比较
    网络设计师训练资料
    802.11b/11a/11g横向比较
    交换机术语
    无线局域网技术白皮书
    无线网络基础知识
    校验码
  • 原文地址:https://www.cnblogs.com/edzjx/p/12270276.html
Copyright © 2011-2022 走看看