源码版本: .Net Core 3.1.14

上篇文章: 【.Net Core】.Net Core 源码分析与深入理解 - 入口 Program.cs (一)

注意:本篇文章主要研究的是 Startup.cs 中做了什么,Configure里面是怎么配置管道的,各种参数到底有何功能。

具体Configure的源码探究比较复杂,准备再仔细学习一下,等下一章 【.Net Core】.Net Core 源码分析与深入理解 - 管道核心 Configure(三)。

可以看到Startup.cs 的代码如下,接下来将会从执行顺序逐一分析。

        public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; } public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
} public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}

IConfiguration:应用程序的各种配置信息。

IApplicationBuilder:获取应用程序中的环境变量,配置Http请求管道。

IHostingEnvironment:包含应用程序宿主环境相关信息的接口。

Startup Constructor 构造函数

首先是构造函数注入进来的Configuration对像,这个对象的加载进了不同类型的配置信息,通过统一的抽象接口进行管理。比如说可以在appsettings.json中配置数据库连接信息,在这里使用配置好的信息。

IConfiguration的源码如下,地址  ......\extensions-3.1.14\src\Configuration\Config.Abstractions\src\IConfiguration

 /// <summary>
/// Represents a set of key/value application configuration properties.
/// </summary>
public interface IConfiguration
{
/// <summary>
/// Gets or sets a configuration value.
/// </summary>
/// <param name="key">The configuration key.</param>
/// <returns>The configuration value.</returns>
string this[string key] { get; set; } /// <summary>
/// Gets a configuration sub-section with the specified key.
/// </summary>
/// <param name="key">The key of the configuration section.</param>
/// <returns>The <see cref="IConfigurationSection"/>.</returns>
/// <remarks>
/// This method will never return <c>null</c>. If no matching sub-section is found with the specified key,
/// an empty <see cref="IConfigurationSection"/> will be returned.
/// </remarks>
IConfigurationSection GetSection(string key); /// <summary>
/// Gets the immediate descendant configuration sub-sections.
/// </summary>
/// <returns>The configuration sub-sections.</returns>
IEnumerable<IConfigurationSection> GetChildren(); /// <summary>
/// Returns a <see cref="IChangeToken"/> that can be used to observe when this configuration is reloaded.
/// </summary>
/// <returns>A <see cref="IChangeToken"/>.</returns>
IChangeToken GetReloadToken();
}

它有以下三个方法:

  • GetChildren():获取直接子配置子节
  • GetReloadToken():返回一个IChangeToken,可用于确定何时重新加载配置
  • GetSection(String):获取指定键的子节点

ConfigureServices

  接下来主要说一下方法里面配置的是什么,重点在于参数是什么,怎么来的,这个方法的参数是IServiceCollection,是一个非常重要的对象,这是一个原生的Ioc容器,所有需要用到的服务都可以注册到里面, 调用service.AddXXXX方法,比如数据库、MVC、跨域、swagger、过滤器等Middleware。

这个IServiceCollection 接口,在框架初始建立时,看起来只有 services.AddControllers(); 注册了控制器的服务,其实不然,基本上要用到的服务全都注册在里面。这里如果直接去看IServiceCollection的接口是看不出什么的,这个需要回到入口--Program。

当IHost对象建立后,第二步Build时,执行了以下方法(源码位置......\extensions-3.1.14\src\Hosting\Hosting\src\HostBuilder ):

        public IHost Build()
{
if (_hostBuilt)
{
throw new InvalidOperationException("Build can only be called once.");
}
_hostBuilt = true; BuildHostConfiguration(); // 创建ConfigurationBuilder,并调用_configureHostConfigActions列表进行配置的初始化
CreateHostingEnvironment(); // 构建HostingEnvironment对象,从配置中获取key为applicationName、environment的应用名称和环境名称
CreateHostBuilderContext(); // HostBuilderContext宿主上下文,保存HostingEnvironment、Configuration和宿主的一些自定义属性
BuildAppConfiguration();    // 合并之前的_hostConfiguration,调用_configureAppConfigActions列表初始化应用配置
CreateServiceProvider(); return _appServices.GetRequiredService<IHost>();
}

可以看到主要执行了5个方法,但是重要的是最后一个方法  CreateServiceProvider()。

        private void CreateServiceProvider()
{
var services = new ServiceCollection();
#pragma warning disable CS0618 // Type or member is obsolete
services.AddSingleton<IHostingEnvironment>(_hostingEnvironment);
#pragma warning restore CS0618 // Type or member is obsolete
services.AddSingleton<IHostEnvironment>(_hostingEnvironment);
services.AddSingleton(_hostBuilderContext);
// register configuration as factory to make it dispose with the service provider
services.AddSingleton(_ => _appConfiguration);
#pragma warning disable CS0618 // Type or member is obsolete
services.AddSingleton<IApplicationLifetime>(s => (IApplicationLifetime)s.GetService<IHostApplicationLifetime>());
#pragma warning restore CS0618 // Type or member is obsolete
services.AddSingleton<IHostApplicationLifetime, ApplicationLifetime>();
services.AddSingleton<IHostLifetime, ConsoleLifetime>();
services.AddSingleton<IHost, Internal.Host>();
services.AddOptions();
services.AddLogging(); foreach (var configureServicesAction in _configureServicesActions)
{
configureServicesAction(_hostBuilderContext, services);
} var containerBuilder = _serviceProviderFactory.CreateBuilder(services); foreach (var containerAction in _configureContainerActions)
{
containerAction.ConfigureContainer(_hostBuilderContext, containerBuilder);
} _appServices = _serviceProviderFactory.CreateServiceProvider(containerBuilder); if (_appServices == null)
{
throw new InvalidOperationException($"The IServiceProviderFactory returned a null IServiceProvider.");
} // resolve configuration explicitly once to mark it as resolved within the
// service provider, ensuring it will be properly disposed with the provider
_ = _appServices.GetService<IConfiguration>();
}

从第一句,var services = new ServiceCollection();,可以看出来了,我们在Startup.cs中的 IServiceCollection 服务容器是这里创建并初始化的。

接下来都是注册前面4个方法BuildHostConfiguration() CreateHostingEnvironment()CreateHostBuilderContext()BuildAppConfiguration()所加工出来的各种信息。

            services.AddSingleton<IHostingEnvironment>(_hostingEnvironment);
services.AddSingleton<IHostEnvironment>(_hostingEnvironment);
services.AddSingleton(_hostBuilderContext);
services.AddSingleton(_ => _appConfiguration);

Host的IHostApplicationLifetime和IHostLifetime这两个接口可以用来进行应用程序的生命周期管理。

这里不细究,详情可参考    探索 ASP.Net Core 3.0系列五:引入IHostLifetime并弄清Generic Host启动交互

            services.AddSingleton<IHostApplicationLifetime, ApplicationLifetime>();
services.AddSingleton<IHostLifetime, ConsoleLifetime>();

接下来几句话 分别是:

注册IHost进服务容器,IHost的默认实现是一个内部类Host

注册Options(一个类似Configuration功能的服务,这里不细讲)

注册默认日志容器

            services.AddSingleton<IHost, Internal.Host>();
services.AddOptions();
services.AddLogging();

后面是调用_configureServicesActions列表把其他服务注册进来......这里打住,我们知道了在ConfigureServices中配置了很多东西就可以了。

Configure

configure方法用于指定应用程序如何响应HTTP请求。通过将中间件组件添加到IApplicationBuilder实例来配置请求管道。

可以配置跨域、静态文件访问、HTTP重定向、异常处理等,如下图所示

接下来请看.Net Core 3.1 ,Configure的的代码如下:主要参数是 IApplicationBuilder ,IWebHostEnvironment 。

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}

IWebHostEnvironment 包含各种配置中要使用到的环境变量。

IApplicationBuilder 是重点,Configure 方法 使用 IApplicationBuilder 来使用中间件,使用 app.Use______ 来注册中间件请求管道

IApplicationBuilder 的源码如下:......\aspnetcore-3.1.14\src\Http\Http.Abstractions\src\IApplicationBuilder

    public interface IApplicationBuilder
{
IServiceProvider ApplicationServices { get; set; }
IDictionary<string, object> Properties { get; }
IFeatureCollection ServerFeatures { get; }

RequestDelegate Build();
IApplicationBuilder New();
IApplicationBuilder Use(Func<RequestDelegate, RequestDelegate> middleware);
}

先说注入的三个参数

ApplicationServices :获取或设置提供对应用程序服务容器的访问的 IServiceProvider 提供程序,为其他对象提供自定义支持的对象,可以参考 https://www.cnblogs.com/watermoon2/p/5075002.html

Properties:获取可用于在中间件之间共享数据的 键/值 集合,Properties 是类型为 IDictionary<string,object>。

ServerFeatures:获取应用程序服务器提供的HTTP特性集。

然后是三个方法

Build():可以看到这个方法是一个委托,使用此委托来处理HTTP请求

New():创建一个 IApplicationBuilder 共享 Properties 的 IApplicationBuilder

Use():将中间件委托添加到应用程序的请求管道中。

以上合起来就是Configure方法会调用ServiceProvider所解析的相应的参数,再可以使用IApplicationBuilder将中间件添加到应用程序管道中。最终RequestDelegate由IApplicationBuilder构建并返回的。

最后用一张图总结一下HTTP请求在中间件管道中的流程:

【.Net Core】.Net Core 源码分析与深入理解 - 配置中心 Startup.cs (二)的更多相关文章

  1. Heritrix源码分析(十三) Heritrix的控制中心(大脑)CrawlController(二)

    本博客属原创文章,欢迎转载!转载请务必注明出处:http://guoyunsky.iteye.com/blog/650744      本博客已迁移到本人独立博客: http://www.yun5u. ...

  2. 使用react全家桶制作博客后台管理系统 网站PWA升级 移动端常见问题处理 循序渐进学.Net Core Web Api开发系列【4】:前端访问WebApi [Abp 源码分析]四、模块配置 [Abp 源码分析]三、依赖注入

    使用react全家桶制作博客后台管理系统   前面的话 笔者在做一个完整的博客上线项目,包括前台.后台.后端接口和服务器配置.本文将详细介绍使用react全家桶制作的博客后台管理系统 概述 该项目是基 ...

  3. HDFS源码分析数据块复制监控线程ReplicationMonitor(二)

    HDFS源码分析数据块复制监控线程ReplicationMonitor(二)

  4. 学习JUC源码(3)——Condition等待队列(源码分析结合图文理解)

    前言 在Java多线程中的wait/notify通信模式结尾就已经介绍过,Java线程之间有两种种等待/通知模式,在那篇博文中是利用Object监视器的方法(wait(),notify().notif ...

  5. springMVC源码分析--HandlerMethodReturnValueHandlerComposite返回值解析器集合(二)

    在上一篇博客springMVC源码分析--HandlerMethodReturnValueHandler返回值解析器(一)我们介绍了返回值解析器HandlerMethodReturnValueHand ...

  6. Mybatis源码分析--关联表查询及延迟加载原理(二)

    在上一篇博客Mybatis源码分析--关联表查询及延迟加载(一)中我们简单介绍了Mybatis的延迟加载的编程,接下来我们通过分析源码来分析一下Mybatis延迟加载的实现原理. 其实简单来说Myba ...

  7. netty源码分析之揭开reactor线程的面纱(二)

    如果你对netty的reactor线程不了解,建议先看下上一篇文章netty源码分析之揭开reactor线程的面纱(一),这里再把reactor中的三个步骤的图贴一下 reactor线程 我们已经了解 ...

  8. RocketMQ源码分析之RocketMQ事务消息实现原理上篇(二阶段提交)

    在阅读本文前,若您对RocketMQ技术感兴趣,请加入 RocketMQ技术交流群 根据上文的描述,发送事务消息的入口为: TransactionMQProducer#sendMessageInTra ...

  9. 【源码分析】FastJson全局配置日期格式导致@JSONField(format = "yyyy-MM-dd")注解失效

    出现的问题 我全局配置的时间格式是:yyyy-MM-dd HH:mm:ss @JSONField注解配置的时间格式是:yyyy-MM-dd 最终的返回结果是:yyyy-MM-dd HH:mm:ss 问 ...

  10. Java ArrayList源码分析(有助于理解数据结构)

    arraylist源码分析 1.数组介绍 数组是数据结构中很基本的结构,很多编程语言都内置数组,类似于数据结构中的线性表 在java中当创建数组时会在内存中划分出一块连续的内存,然后当有数据进入的时候 ...

随机推荐

  1. [转帖]rsync参数详解

    最近经常需要传送文件,学习到rsync这个非常好用的工具.rsync的传输方不像是scp复制粘贴,而是是创建一个镜像,所以在传输效率上比scp命令要快很多,缺点就是对文件的属性如权限.用户.组.时间戳 ...

  2. [转帖]一本正经的八卦一下CPU的自主可控 之二

    https://zhuanlan.zhihu.com/p/62399200 一本正经的八卦一下CPU的自主可控 之二 上回书说到CPU自主可控第一个层面的指令集问题.这回聊一聊接下来的设计问题. 第二 ...

  3. sshpass 免密码进行文件复制的方法

    1. 部分centos8 没有安装 sshpass 需要先安装 sshpass yum install sshpass 2. 需要增加一个配置文件, 避免因为 stickhost 检查 造成命令失效 ...

  4. date的命令使用.

    date命令的使用 1.直接用date命令显示日期时间 在命令行中输入date然后回车,显示结果"Wed Aug 7 08:58:07 CST 2019".这是系统根据设定的时区显 ...

  5. 从一次CPU打满到ReDos攻击和防范

    作者:京东物流 刘海茂 近期碰到一起值班报警事件,web 应用服务器 CPU 消耗打到 99%,排查后发现是因为 ReDoS 导致了服务器发生了资源被耗尽.访问系统缓慢的问题,通过排查过程从而分享下 ...

  6. css3中的圆角border-radius

    css3的属性应该加上浏览器前缀 不同的浏览器内核不同,因此css的前缀不同. 常见的几种浏览器内核 火狐浏览器 Geoko内核 前缀是 -mox- 谷歌浏览器, Webkit内核 前缀是 -wekb ...

  7. Golang zip压缩文件读写操作

    创建zip文件 golang提供了archive/zip包来处理zip压缩文件,下面通过一个简单的示例来展示golang如何创建zip压缩文件: func createZip(filename str ...

  8. HEVC扩展备用安装方法

    这个玩意微软商店免费但是下架了,购买需要RMB 安装 转到 https://store.rg-adguard.net/ 在左侧的下拉菜单选择"ProductId" 把链接中&quo ...

  9. hydra 密码爆破工具入门

    Hydra(九头蛇海德拉)是希腊神话之中的一个怪兽,以九个头闻名于世,在Kali中hydray(hai der rua) 是默认被安装的,该工具是密码破解的老司机,可以破解各种登录密码,非常怪兽,但是 ...

  10. 【分享】从Mybatis源码中,学习到的10种设计模式

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言:小镇卷码家 总有不少研发伙伴问小傅哥:"为什么学设计模式.看框架源码.补技 ...