在这个特殊的春节,大家想必都在家出不了们,远看已经到了回城里上班的日子,但是因为一只蝙蝠的原因导致我们无法回到工作岗位,大家可能有的在家远程办公,有些在家躺着看书,有的是在家打游戏;在这个特殊无聊的日志,我果断从无聊的被窝中 开启了流量共享wifi 来进行.net core 3.1 源代码的解读和学习,并且把学习到的东西分享给大家。

疑问

刚刚接触ASP.NET CORE 项目的同学可能会有如下疑问:

  • ASP.NET CORE 项目的启动过程是怎么样的?
  • 为什么ASP.NET CORE项目可以在控制台中运行启动后变成了一个网站程序?

现在我这里使用.NETCORE 3.1 最新稳定发布版本来进行以上问题的解析,带大家解决以上问题的疑惑,学习完大家可以对ASP.NETCORE 项目会有一个不一样的理解和领悟.


启动过程

刚刚接触ASP.NET core 的同学们估计都会觉得和之前的ASP.NET 设计大不一样,代码风格也有很大的变化,以前的ASP.NET 是全家桶框架模式,里面包含了所有的实现,你用的到的用不到的都集成在里面;然而ASP.NET CORE 框架做了大的改变,以最小化抽象设计,通过扩展方法完成易用性扩展.

解读过源代码的同学们都可以发现大多api都是最小化单元抽象接口方式进行设计,其他复杂的方法api都是通过扩展方法进行扩展提供,这也是.NET Core 高效易扩展的一大优势原因.

对于ASP.NET Core应用程序来说,我们要记住非常重要的一点是:其本质上是一个独立的控制台应用,它并不是必需在IIS内部托管且并不需要IIS来启动运行(而这正是ASP.NET Core跨平台的基石)。ASP.NET Core应用程序拥有一个内置的Self-Hosted(自托管)Web Server(Web服务器),用来处理外部请求。

不管是托管还是自托管,都离不开Host(宿主)。在ASP.NET Core应用中通过配置并启动一个Host来完成应用程序的启动和其生命周期的管理。而Host的主要的职责就是Web Server的配置和Pilpeline(请求处理管道)的构建。

我们现在来创建一个ASP.NETCORE WEB 项目 步骤如下

文件-> 新建 -> 项目 -> 选择ASP.Net Core Web应用程序 -> 选择.NETCORE 3.1 框架 如图:

创建项目后我们从Program 类中可以看到以下代码:

public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
} public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)//开启一个默认的通用主机Host建造者
.ConfigureWebHostDefaults(webBuilder =>
{
// 从前缀为“ASPNETCORE” 环境变量加载WEB主机配置
// 默认是Kestrel 设置为web 服务器并对其进行默认配置, 支持iis集成
//注册系统启动所使用的组件,比如配置的组件,容器的组件等
webBuilder.UseStartup<Startup>();
});
}

查看以上代码可以发现 Main 方法中代码很简单 ,清晰可见

CreateHostBuilder(args) :方法创建了一个IHostBuilder 抽象对象,创建过程包含CreateDefaultBuilder(args) :开启创建一个默认的通用宿主机Host建造者,再通过ConfigureWebHostDefaults()方法配置开启默认的Kestrel 为默认的Web服务器并对其进行默认配置,并集成对iis的集成

Build() :负责创建IHost,看过源代码的同学可以发现Build的过程 会配置各种东西,本身通过管道模式进行了一系列的默认或者自定义的配置以及服务注册的构建(下面会详细讲解)

Run() :启动IHost

所以,ASP.NET Core应用的启动本质上是启动作为宿主的Host对象。

其主要涉及到两个关键对象IHostBuilderIHost,它们的内部实现是ASP.NET Core应用的核心所在。下面我们就结合源码并梳理调用堆栈来一探究竟!

源代码详细图如下:

从上图中我们可以看出CreateDefaultBuilder()方法主要干了五件大事:
  • UseContentRoot:指定Web host使用的content root(内容根目录),比如Views。默认为当前应用程序根目录。
  • ConfigureHostConfiguration :启动时宿主机需要的环境变量等相关,支持命令行
  • ConfigureAppConfiguration:设置当前应用程序配置。主要是读取 appsettinggs.json 配置文件、开发环境中配置的UserSecrets、添加环境变量和命令行参数 。
  • ConfigureLogging:读取配置文件中的Logging节点,配置日志系统。
  • UseDefaultServiceProvider:设置默认的依赖注入容器。
从图中可以看出CreateDefaultBuilder 后调用了ConfigureWebHostDefaults 方法,该方法默认主要做了以下几个事情
  • UseStaticWebAssets:静态文件环境的配置启用
  • UseKestrel:开启Kestrel为默认的web 服务器.
  • ConfigureServices:服务中间件的注册,包含路由的中间件的注册
  • UseIIS:对iis 集成的支持
  • UseStartup:程序Startup 启动,该启动类中可以注册中间件、扩展第三方中间件,以及相关应用程序配置的处理等等操作
现在所有的配置都已经配置创建好了,接下来我们来看看Build 方法主要做了哪些不为人知的事情,先来看下源代码
/// <summary>
/// Run the given actions to initialize the host. This can only be called once.
/// </summary>
/// <returns>An initialized <see cref="IHost"/></returns>
public IHost Build()
{
if (_hostBuilt)
{
throw new InvalidOperationException("Build can only be called once.");
}
_hostBuilt = true; BuildHostConfiguration();
CreateHostingEnvironment();
CreateHostBuilderContext();
BuildAppConfiguration();
CreateServiceProvider(); return _appServices.GetRequiredService<IHost>();
}

从代码中可以发现有一个_hostBuilt 的变量,细心的同学可以发现该变量主要是用于控制是否build 过,所以这里可以大胆猜测只能build 一次该Host;现在看下源代码解析图:

经过查看源代码得到的执行结构如上,因此我把代码改造成如下结构。

public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
} public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)//开启一个默认的通用主机Host建造者
.ConfigureAppConfiguration(config => {
//注册应用程序内所使用的配置文件,比如数据库链接等等
Console.WriteLine("ConfigureAppConfiguration");
})
.ConfigureServices(service =>
{
//注册服务中间件等操作
Console.WriteLine("ConfigureServices");
})
.ConfigureHostConfiguration(builder => {
//启动时需要的组件配置等,比如监听的端口 url地址等
Console.WriteLine("ConfigureHostCOnfiguration");
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}

Startup 代码如下:

public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
Console.WriteLine("Startup ");
} public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
Console.WriteLine("ConfigureServices");
services.AddControllersWithViews();
} // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
Console.WriteLine("Configure");
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles(); app.UseRouting(); app.UseAuthorization(); app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
}
}

通过执行发现执行代码顺序正如我们源代码的执行顺序一致,执行顺序如下图:

为何通过控制台命令运行后自动启动了一个网站程序?

以前ASP.NET web项目是需要搭建在iis 中托管运行,但是ASP.NETCORE 项目可以直接通过命令行进行托管运行,运行后可以直接浏览器打开,你们有没有考虑过为什么?,细心的同学查看项目属性也会发现项目的输出类型也是控制台项目,如图:

查看这图,有没有发现很神奇,为什么输出类型竟然可以通过控制台命令行进行启动项目呢?

在上面的源代码分析过程中可以发现启动时会启动一个Kestrel 服务器(ConfigureWebHostDefaults方法中会调用UseKestrel),所以命令后启动一个控制台应用程序后相当于启动了一台web服务器;下面简要的概括下Kestrel 服务器的优势:

  • Kestrel:Kestrel 是个精简高效的 HttpServer,以包形式提供,自身不能单独运行。

内部封装了对 libuv 的调用,作为I/O底层,屏蔽各系统底层实现差异;有了Kestrel才能真正的实现跨平台.

好了,想必同学们到这里已经对上面 两个疑惑有了清晰的答案了。这里我抛出一个疑问,看了上面的代码解读,大家有没有发现ASP.NET CORE 和ASP.NET 有了很大的不同,这是什么样的设计改进呢?敬请期待下期我们一起来学习ASP.NET CORE 的牛逼的管道模型.

ASP.NET CORE 启动过程及源码解读的更多相关文章

  1. 各类最新Asp .Net Core 项目和示例源码

    1.网站地址:http://www.freeboygirl.com2.网站Asp .Net Core 资料http://www.freeboygirl.com/blog/tag/asp%20net%2 ...

  2. SpringBoot启动嵌入式tomcat源码解读

    一.SpringBoot自动拉起Tomcat SpringBoot框架是当前比较流行的java后端开发框架,与maven结合大大简化了开发人员项目搭建的步骤,我们知道SpringBoot的启动类启动后 ...

  3. spring mvc 启动过程及源码分析

    由于公司开源框架选用的spring+spring mvc + mybatis.使用这些框架,网上都有现成的案例:需要那些配置文件.每种类型的配置文件的节点该如何书写等等.如果只是需要项目能够跑起来,只 ...

  4. ASP.Net Core Configuration 理解与源码分析

    Configuration 在ASP.NET Core开发过程中起着很重要的作用,这篇博客主要是理解configuration的来源,以及各种不同类型的configuration source是如何被 ...

  5. Hyperledger Fabric的test-network启动过程Bash源码详解

    前言 在基于Debian搭建Hyperledger Fabric 2.4开发环境及运行简单案例中,我们已经完成了Fabric 2.4的环境搭建及fabric-samples/test-network官 ...

  6. Netty服务端启动过程相关源码分析

    1.Netty 是怎么创建服务端Channel的呢? 我们在使用ServerBootstrap.bind(端口)方法时,最终调用其父类AbstractBootstrap中的doBind方法,相关源码如 ...

  7. 从SpringBoot启动,阅读源码设计

    目录 一.背景说明 二.SpringBoot工程 三.应用上下文 四.资源加载 五.应用环境 六.Bean对象 七.Tomcat服务 八.事件模型 九.配置加载 十.数据库集成 十一.参考源码 服务启 ...

  8. Asp.Net Core AuthorizeAttribute 和AuthorizeFilter 跟进及源码解读

    一.前言 IdentityServer4已经分享了一些应用实战的文章,从架构到授权中心的落地应用,也伴随着对IdentityServer4掌握了一些使用规则,但是很多原理性东西还是一知半解,故我这里持 ...

  9. Taurus.MVC 支持Asp.Net Core 的过程

    前言: 这些天,似乎.NET Core相关的新闻和文章经常在我眼前晃~~~ 昨天,微软又发布了.Core 2.1,又愰了一下,差点没亮瞎我的眼睛. 好吧,大概是上天给我的暗示,毕竟 CYQ.Data  ...

随机推荐

  1. idea发布web项目在tomcat位置问题

    (1)war模式这种可以称之为是发布模式,看名字也知道,这是先打成war包,再发布. (2)war exploded模式是直接把文件夹.jsp页面 .classes等等移到Tomcat 部署文件夹里面 ...

  2. [USACO09DEC]音符Music Notes (二分、STL)

    https://www.luogu.org/problem/P2969 题目描述 FJ is going to teach his cows how to play a song. The song ...

  3. 二十四、SSH介绍

    1.ssh介绍: SSH先对联机数据包通过加密技术进行加密处理,加密后在进行数据传输,确保了传递的数据安全.(运维的一大重视点就是要对安全敏感) 在当前的生产环境运维工作中,绝大多数企业都是SSH协议 ...

  4. token和refresh token

    https://www.cnblogs.com/minirice/p/9232355.html 在spring boot中结合OAuth2使用JWT时,刷新token时refresh token一直变 ...

  5. ACM-ICPC Nanjing Onsite 2018 I. Magic Potion

    题意:类似二分图匹配给的题目,不过这次在这里给出了k,表示没人可以再多一次匹配机会,这次匹配不能用上一次被匹配的对象 分析:不能用匈牙利做俩次匹配,因为俩次的最大匹配并不等价于总和的匹配,事实证明,你 ...

  6. Excel-DNA项目只用1个文件实现Ribbon CustomUI和CustomTaskpane定制【C#版】

    Excel-DNA项目中的自定义功能区和自定义任务窗格需要用到各种命名空间.添加所需文件,才能实现.后来我发现可以把所有代码都写在Class1.cs这个默认文件中. 大家可以在Visual Studi ...

  7. Arcpy处理修改shapefile FeatureClass 线要素坐标

    需求:在开发的webgis系统中需要将道路矢量数据与谷歌地图瓦片叠加,谷歌地图瓦片在国家测绘局的要求是进行了偏移处理的,人称“火星坐标系GCJ_02”,道路数据是WGS-84坐标系下的经纬度坐标,现在 ...

  8. maven-assembly-plugin 打包包含多余依赖问题一则

    有同事反馈自己maven-assembly-plugin打的包里面多了很多mvn dependency:tree中没有的jar. 我当时只是试着把他的maven-assembly-plugin更新到了 ...

  9. F. Moving On

    http://codeforces.com/gym/102222/problem/F fory #include<bits/stdc++.h> using namespace std; t ...

  10. [LC] 81. Search in Rotated Sorted Array II

    Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand. (i.e. ...