.NET Core 3.0之深入源码理解Host(一)
写在前面
ASP .NET Core中的通用主机构建器是在v2.1中引入的,应用在启动时构建主机,主机作为一个对象用于封装应用资源以及应用程序启动和生存期管理。其主要功能包括配置初始化(包括加载配置以及配置转换为通用的键值对格式),创建托管环境和Host通用上下文、依赖注入等。
在.NET Core 3.0中采用了IHostBuilder用于创建Host,同时也不再建议使用Web主机,而建议使用泛型主机,主要原因是原有的通用主机仅适用于非HTTP负载,为了提供更加广泛的主机方案,需要将HTTP管道与Web主机的接口分离出来。但Web主机仍会向后兼容。

.NET Core 3.0中创建通用主机
以下代码是V3.0中提供的模板代码,可以看到在创建主机的过程中,已经摒弃了WebHostBuilder的创建方式
1: public class Program
2: {
3: public static void Main(string[] args)
4: {
5: CreateHostBuilder(args).Build().Run();
6: }
7:
8: public static IHostBuilder CreateHostBuilder(string[] args) =>
9: Host.CreateDefaultBuilder(args)
10: .ConfigureWebHostDefaults(webBuilder =>
11: {
12: webBuilder.UseStartup<Startup>();
13: });
14: }
而在.NET Core 2.X中
1: public class Program
2: {
3: public static void Main(string[] args)
4: {
5: CreateWebHostBuilder(args).Build().Run();
6: }
7:
8: public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
9: WebHost.CreateDefaultBuilder(args)
10: .UseStartup<Startup>();
11: }
V3.0模板中提供的CreateHostBuilder()方法看起来非常类似于V2.X中的CreateWebHostBuilder()。
其主要区别在于对WebHost.CreateDefaultBuilder()由Host.CreateDefaultBuilder()替换。使用CreateDefaultBuilder()辅助方法可以非常轻松地从v2.x切换到v3.0。
另一个区别是关于ConfigureWebHostDefaults()的调用。由于新的主机构建器是通用主机构建器,因此我们必须让它知道我们打算为Web主机配置默认设置。这些默认配置我们可以在ConfigureWebHostDefaults()方法中实现
CreateDefaultBuilder
该方法Microsoft.Extensions.Hosting.Host中,它是一个静态类,里面有两个方法,一个有参的CreateDefaultBuilder(string[] args),一个是无参的。
无参方法源码如下,
1: public static IHostBuilder CreateDefaultBuilder() =>
2: CreateDefaultBuilder(args: null);
可以看到该方法实际上是设置了默认值。
IHostBuilder CreateDefaultBuilder(string[] args)方法主要有以下功能:
创建HostBuilder对象
1: var builder = new HostBuilder();
指定Host要使用的内容根目录
1: builder.UseContentRoot(Directory.GetCurrentDirectory());
配置初始化(环境变量、appsettings.json、User Secrets)
1: builder.ConfigureHostConfiguration(config =>
2: {
3: config.AddEnvironmentVariables(prefix: "DOTNET_");
4: if (args != null)
5: {
6: config.AddCommandLine(args);
7: }
8: });
9:
10: builder.ConfigureAppConfiguration((hostingContext, config) =>
11: {
12: var env = hostingContext.HostingEnvironment;
13:
14: config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
15: .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
16:
17: if (env.IsDevelopment() && !string.IsNullOrEmpty(env.ApplicationName))
18: {
19: var appAssembly = Assembly.Load(new AssemblyName(env.ApplicationName));
20: if (appAssembly != null)
21: {
22: config.AddUserSecrets(appAssembly, optional: true);
23: }
24: }
25:
26: config.AddEnvironmentVariables();
27:
28: if (args != null)
29: {
30: config.AddCommandLine(args);
31: }
32: })
日志
1: .ConfigureLogging((hostingContext, logging) =>
2: {
3: logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
4: logging.AddConsole();
5: logging.AddDebug();
6: logging.AddEventSourceLogger();
7: })
在开发环境模式下启用作用域验证
1: .UseDefaultServiceProvider((context, options) =>
2: {
3: var isDevelopment = context.HostingEnvironment.IsDevelopment();
4: options.ValidateScopes = isDevelopment;
5: options.ValidateOnBuild = isDevelopment;
6: });
Build
Build()方法是Microsoft.Extensions.Hosting中,并且该方法只会执行一次,当然这种一次只是在同一个实例里面
1: public IHost Build()
2: {
3: if (_hostBuilt)
4: {
5: throw new InvalidOperationException("Build can only be called once.");
6: }
7: _hostBuilt = true;
8:
9: BuildHostConfiguration();
10: CreateHostingEnvironment();
11: CreateHostBuilderContext();
12: BuildAppConfiguration();
13: CreateServiceProvider();
14:
15: return _appServices.GetRequiredService<IHost>();
16: }
该方法主要是包括以下功能:
创建HostingEnvironment
创建HostBuilderContext
配置初始化及格式标准化
DI(创建IHostEnvironment、IHostApplicationLifetime、IHostLifetime、IHost)
Run
Run方法运行应用程序并阻止调用线程,直到主机关闭
1: public static void Run(this IHost host)
2: {
3: host.RunAsync().GetAwaiter().GetResult();
4: }
以下是RunAsync的源码,此处可以通过设置CancellationToken的值,使应用程序自动关闭
1: public static async Task RunAsync(this IHost host, CancellationToken token = default)
2: {
3: try
4: {
5: await host.StartAsync(token);
6:
7: await host.WaitForShutdownAsync(token);
8: }
9: finally
10: {
11: #if DISPOSE_ASYNC
12: if (host is IAsyncDisposable asyncDisposable)
13: {
14: await asyncDisposable.DisposeAsync();
15: }
16: else
17: #endif
18: {
19: host.Dispose();
20: }
21:
22: }
23: }
.NET Core 3.0之深入源码理解Host(一)的更多相关文章
- .NET Core 3.0之深入源码理解Host(二)
写在前面 停了近一个月的技术博客,随着正式脱离996的魔窟,接下来也正式恢复了.本文从源码角度进一步讨论.NET Core 3.0 中关于Host扩展的一些技术点,主要讨论Long Run Pro ...
- .NET Core 3.0之深入源码理解Startup的注册及运行
原文:.NET Core 3.0之深入源码理解Startup的注册及运行 写在前面 开发.NET Core应用,直接映入眼帘的就是Startup类和Program类,它们是.NET Core应用程 ...
- .NET Core 3.0之深入源码理解Configuration(一)
Configuration总体介绍 微软在.NET Core里设计出了全新的配置体系,并以非常灵活.可扩展的方式实现.从其源码来看,其运行机制大致是,根据其Source,创建一个Builder实例,并 ...
- .NET Core 3.0之深入源码理解Kestrel的集成与应用(一)
写在前面 ASP.NET Core 的 Web 服务器默认采用Kestrel,这是一个基于libuv(一个跨平台的基于Node.js异步I/O库)的跨平台.轻量级的Web服务器. 在开始之前,先回 ...
- .NET Core 3.0之深入源码理解Kestrel的集成与应用(二)
前言 前一篇文章主要介绍了.NET Core继承Kestrel的目的.运行方式以及相关的使用,接下来将进一步从源码角度探讨.NET Core 3.0中关于Kestrel的其他内容,该部分内容,我们 ...
- .NET Core 3.0之深入源码理解HttpClientFactory(二)
写在前面 上一篇文章讨论了通过在ConfigureServices中调用services.AddHttpClient()方法,并基于此进一步探讨了DefaultHttpClientFactory是 ...
- .NET Core 3.0之深入源码理解ObjectPool(一)
写在前面 对象池是一种比较常用的提高系统性能的软件设计模式,它维护了一系列相关对象列表的容器对象,这些对象可以随时重复使用,对象池节省了频繁创建对象的开销. 它使用取用/归还的操作模式,并重复执行这些 ...
- .NET Core 3.0之深入源码理解HealthCheck(一)
写在前面 我们的系统可能因为正在部署.服务异常终止或者其他问题导致系统处于非健康状态,这个时候我们需要知道系统的健康状况,而健康检查可以帮助我们快速确定系统是否处于正常状态.一般情况下,我们会提供公开 ...
- .NET Core 3.0之深入源码理解Configuration(三)
写在前面 上一篇文章讨论了文件型配置的基本内容,本篇内容讨论JSON型配置的实现方式,理解了这一种配置类型的实现方式,那么其他类型的配置实现方式基本可以触类旁通.看过了上一篇文章的朋友,应该看得出 ...
随机推荐
- c# 窗体开发4 数据库访问技术
ADO.NET的名称起源于ADO(ACTIVEX DATA OBJECTS) USING SYSTEM; USING SYSTEM.COLLECTIONS.GENERIC; USING SYSTEM. ...
- 题解 CF1206B 【Make Product Equal One】
感谢 @一个低调的人 (UID=48417) 题目: CodeForces链接 Luogu链接 思路: 这是一个一眼题 我们不妨把所有的数都看做是\(1\)(取相应的花费,如:\(6\) 的花费就是\ ...
- 时至今日,我们应该承认.Net目前的状况实在堪忧
一: .Net之前 .Net 经历了多年的锤炼,语言特性本身非常优雅和完善,也是非常甜品的一种语言 二: .Net现状 但是与此同时,.Net的生态日益糟糕,困扰着广大.Neter 三: .N ...
- ubuntu下仅仅获取网卡一的ip地址 && shell中字符串拼接
问题描述: ubuntu下仅仅获取网卡一的ip地址 问题背景: eth0,eth1,eth2……代表网卡一,网卡二,网卡三…… lo代表127.0.0.1,即localhost | 问题描述: 已知字 ...
- ios高效开发-正确的使用枚举(Enum)
前言 Enum,也就是枚举,从C语言开始就有了,C++.Java.Objective-C.Swift这些语言,当然都有对应的枚举类型,功能可能有多有少,但是最核心的还是一个—规范的定义代码中的状态.选 ...
- Java修炼——内部类详解
内部类详解 定义:将一个类定义在另一个类的内部,该类就称为内部类 类中定义的内部类特点: 内部类作为外部类的成员,可以直接访问外部类的成员 (包括 private 成员),反之则不行. 内部类做为外部 ...
- Springboot结合Redis
安装 Redis 安装 gcc Yum install gcc-c++ 解压 redis.3.0.0.tar.gz 压缩包 tar -zxvf redis-3.0.0.tar.gz 进入解压后的目 ...
- [TimLinux] Python 使用入门
1. 为什么用Python 软件质量:Python注重可读性.一致性和软件质量. 提高开发者的效率:Python代码的大小往只有C++/Java代码的1/5 ~ 1/3. 程序的可移植性:绝大多数Py ...
- SPOJ Distanct Substrings(求不同子串的数量)
Given a string, we need to find the total number of its distinct substrings. Input T- number of test ...
- 洛谷 题解 P2645 【斯诺克】
吐槽一下这道题: 数据太水了!!! 请注意,这题如果你考虑了犯规的情况,那么你的分数...可能会和我一样,只有40分. 也就是说,这是一篇AC不了这道题的题解!!! 现在,我来讲一下这道题的正解: 两 ...