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

    参考网址:https://blog.csdn.net/edzjx/article/details/104257596

    本文分析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官方文档


    ————————————————
    版权声明:本文为CSDN博主「伊一线天」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/edzjx/article/details/104257596

  • 相关阅读:
    7月23日 R进行层次聚类算法的继续完善
    明天学习的内容
    MySql快速导出为excel文件
    数据挖掘的隐私边界 【转自《中欧商业评论》】
    【转】Data truncation: Truncated incorrect DOUBLE value:Mysql Update时
    7月20日下一步工作
    R对term进行kmeans聚类完整实例(tm包)
    数学之美 系列一 统计语言模型
    7月30日总结
    MathType输入Support 自动分开的问题
  • 原文地址:https://www.cnblogs.com/bruce1992/p/15187544.html
Copyright © 2011-2022 走看看