本文分析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         }