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官方文档
asp.net core 3.1 入口:Program.cs中的Main函数的更多相关文章
- 如何在 asp.net core 3.x 的 startup.cs 文件中获取注入的服务
一.前言 从 18 年开始接触 .NET Core 开始,在私底下.工作中也开始慢慢从传统的 mvc 前后端一把梭,开始转向 web api + vue,之前自己有个半成品的 asp.net core ...
- 【Azure 应用服务】App Service .NET Core项目在Program.cs中自定义添加的logger.LogInformation,部署到App Service上后日志不显示Log Stream中的问题
问题描述 在.Net Core 5.0 项目中,添加 Microsoft.Extensions.Logging.AzureAppServices 和 Microsoft.Extensions.Logg ...
- ASP.NET Core框架揭秘(持续更新中…)
之前写了一系列关于.NET Core/ASP.NET Core的文章,但是大都是针对RC版本.到了正式的RTM,很多地方都发生了改变,所以我会将之前发布的文章针对正式版本的.NET Core 1.0进 ...
- ASP.NET Core框架揭秘(持续更新中…)
之前写了一系列关于.NET Core/ASP.NET Core的文章,但是大都是针对RC版本.到了正式的RTM,很多地方都发生了改变,所以我会将之前发布的文章针对正式版本的.NET Core 1.0进 ...
- 【Asp.Net Core】在Visual Studio 2017中使用Asp.Net Core构建Angular4应用程序
前言 Visual Studio 2017已经发布了很久了.做为集成了Asp.Net Core 1.1的地表最强IDE工具,越来越受.NET系的开发人员追捧. 随着Google Angular4的发布 ...
- ASP.NET Core 1.0: 指定Static File中的文件作为default page
指定一个网站的default page是很容易的事情.譬如IIS Management中,可以通过default page来指定,而默认的index.html, index.htm之类,则早已经被设置 ...
- 【ASP.NET Core】如何隐藏响应头中的 “Kestrel”
全宇宙人民都知道,ASP.NET Core 应用是不依赖服务器组件的,因此它可以独立运行,一般是使用支持跨平台的 Kestrel 服务器(当然,在 Windows 上还可以考虑用 HttpSys,但要 ...
- Asp.Net Core&Docker部署到树莓派3B中
花了一点时间将吃灰数月的树莓派装上了Docker,并在容器中部署了一个Asp.Net Core应用程序,通过花生壳映射树莓派中的程序,可以使用外网访问树莓派,玩起来很有意思(外网访问地址:http:/ ...
- Asp.Net Core WebAPI+PostgreSQL部署在Docker中
PostgreSQL是一个功能强大的开源数据库系统.它支持了大多数的SQL:2008标准的数据类型,包括整型.数值值.布尔型.字节型.字符型.日期型.时间间隔型和时间型,它也支持存储二进制的大对像, ...
随机推荐
- basic-pentesting-1 靶机提权
原文地址:https://www.payload.com.cn/ basic-pentesting-1 下载地址: https://www.vulnhub.com/entry/basic-pent ...
- Java容器解析系列(15) HashTable Dictionary & Properties
HashTable的实现原理与HashMap没有什么区别; 其与HashMap的主要区别如下: 添加进入jdk时间:HashTable在jdk1.0时添加,HashMap在jdk1.2时添加; 类签名 ...
- HTTP负责均衡模块(HTTP Upstream)
这个模块为后端的服务器提供简单的负载均衡(轮询(round-robin)和连接IP(client IP))如下例: upstream backend { server backend1.examp ...
- day03_流程控制语句
day03_流程控制语句 建议: 凡是次数确定的场景多用for循环,否则用while循环. 三元运算符 由?:符号表示的,具体的含义其实就和if-else结构的含义差不多,这种运算符会将某个条 ...
- centos7下oracle11g详细的安装与建表操作
一.oracle的安装,在官网下载oracle11g R2 1.在桌面单击右键,选择“在终端中打开”,进入终端 输入命令:su 输入ROOT密码: 创建用户组oinstall:groupadd oin ...
- .net core3.1 下由Autofac接管IOC
我们都知道,.net core天生自带IOC容器,但是他的功能其实并不强大,而且有坑:在构造注入的时候,他默认找参数最少的构造函数. 这里,我讲解如何使用Autofac去接管IOC,至于为什么要选Au ...
- Java的Integer与int互转
int转Integer ; Integer wrapperi = new Integer(i); Integer转int ); int i = wrapperi.intValue(); JDK1.5以 ...
- 学习Qt的资源-网站、论坛、博客等
来自<零基础学Qt 4编程>一书的附录 附录C Qt资源 C.1 Qt 官方资源 全球各大公司以及独立开发人员每天都在加入 Qt 的开发社区.他们已经认识到了Qt 的架构本身便可加快应用程 ...
- Codeforces_734_F
http://codeforces.com/problemset/problem/734/F x|y + x&y = x+y. #include<iostream> #includ ...
- HDU6191 Query on A Tree (01字典树+启发式合并)
题意: 给你一棵1e5的有根树,每个节点有点权,1e5个询问(u,x),问你子树u中与x异或最大的值是多少 思路: 自下而上启发式合并01字典树,注意合并时清空trie 线段树.字典树这种结构确定的数 ...