本文分析Program.cs 中Main()函数中代码的运行顺序分析asp.net core程序的启动,重点不是剖析源码,而是理清程序开始时执行的顺序。到底用了哪些实例,哪些法方。html
asp.net core 3.1 的程序入口在项目Program.cs文件里,以下。git
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>(); }); } }
program类是定义在项目根目录Program.cs文件中,全部.net core程序的入口,包括asp.net core 程序。这颇有意思,就有点相似控制端程序。相比以前的web项目没有任何程序入口只有web.config、global这类配置文件和全局文件这种没有程序入口web项目,我以为这类更容易理解asp.net core是怎么工做的。github
在asp.net core 3.1中 的Program类里,定义了2个方法:Main() 和CreateHostBuilder()web
public static void Main(string[] args) { CreateHostBuilder(args).Build().Run(); }
Main() 方法是整个项目的入口方法,就如同C系列语言,全部的程序入口都是。这里main()只有一行代码,可是实际上执行了三个函数C:json
1 IHostBuilder builder= CreateHostBuilder(args); 2 IHost host=builder.Build(); 3 host.Run();
第一行,是定义在Program类的CreateHostBuilder 它主要产生一个IhostBuilder实例builder。api
第二行,经过builder.Build()法方产生一个Ihost实例 host。app
第三含,经过host.Run()方法,开始运行web项目,这时候就能够响应各类请求了。asp.net
而这个过程里最繁琐的就是建立builder,本文重点篇幅就是在这里。ide
此法方经过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 }
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;还有加载日志模块等等。
详细见参考文档二、3,其中.NET Core 3.0之深刻源码理解Host(一),做者从源码角度剖析了此法方,官方文档Host.CreateDefaultBuilder 方法官方说明了法方操做那些内容。
IHoustBuilder.ConfigureWebHostDefaults(Action <IWebHostBuilder>)方法定义在Microsoft.Extensions.Hosting.GenericHostBuilderExtensions静态类中(GenericHostBuilderExtensions.cs),此静态类就定义这一个静态方法。
此处参数configure是一个内置委托Action <IWebHostBuilder>,这个委托的定义就执行一行代码:
webBuilder.UseStartup<Startup>();
其实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静态类中)。
内置委托,在这里对委托进行了定义,主要两行代码:
WebHost.ConfigureWebDefaults(webHostBuilder);
在core2.1中该方法是在CreateHostBuilder()中WebHost.CreateDefaultBuilder(arg)中调用,core3.1,改成Host.ConfigureDefualts(arg)后,经过委托在ConfigureWebHost中调用。由于此方法在委托里调用,在下面章节降到委托执行的时候再详细说明。
configure(webHostBuilder);
就是3.2.1中的
webBuilder.UseStartup<Startup>();
定义在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 }
在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)
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>();
此方法在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类中的配置的信息
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类配置信息
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官方文档