WebApplication 是用于配置HTTP管道和路由的web应用程序,接来下我将一一拆解它的组成。

/// <summary>
/// The web application used to configure the HTTP pipeline, and routes.
/// </summary>
[DebuggerDisplay("{DebuggerToString(),nq}")]
[DebuggerTypeProxy(typeof (WebApplication.WebApplicationDebugView))]
public sealed class WebApplication : IHost,IDisposable,IApplicationBuilder,IEndpointRouteBuilder,IAsyncDisposable

IHost

​ 首先Web应用是一个程序,而 IHost 就是程序的抽象

public interface IHost : IDisposable
{
IServiceProvider Services { get; }
Task StartAsync(CancellationToken cancellationToken = default (CancellationToken));
Task StopAsync(CancellationToken cancellationToken = default (CancellationToken));
}

​ 一个程序具备启动、停止生命周期,这很好理解。我要说的是 IServiceProvider ,他非常关键,后面会在依赖注入章节来详细解释。目前你只需要知道他是一个服务供应商就可以了,就可以通过他获取想要的服务,但前提是你在IOC容器中注册过。

​ Host StartAsync 代码流如下:

await host._hostLifetime.WaitForStartAsync(token1).ConfigureAwait(false); // 注册start程序
host.Services.GetService<IStartupValidator>()?.Validate(); // 校验
IHostedLifecycleService.StartingAsync
IHostedService.StartAsync
IHostedLifecycleService.StartedAsync
host._applicationLifetime.NotifyStarted();

StopAsync 类似,代码流如下:

IHostedLifecycleService.StoppingAsync
IHostedService.StopAsync
IHostedLifecycleService.StoppedAsync
this._logger.StoppedWithException((Exception) ex);

​ 值得注意的是 IStartupValidatorIHostedServiceIHostedLifecycleService 分别为我们提供不同的钩子,只需要向容器注册即可加入我们自定义的业务逻辑。

IApplicationBuilder

WebApplication 实现 IApplicationBuilder 具有pipeline机制。

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

​ 这里要解释一下pipeline,管道是.NET中非常普及的一个概念,内核是切面编程,同样的在后续我们会有专门的章节来例举它。现在你只需要知道,他是一个洋葱模型。

​ 同时,IApplicationBuilder 从命名上就表达了这是一个构建者模式,因此 WebApplication 提供了 Build

public WebApplication Build()
{
this._hostApplicationBuilder.Services.Add(this._genericWebHostServiceDescriptor);
this.Host.ApplyServiceProviderFactory(this._hostApplicationBuilder);
this._builtApplication = new WebApplication(this._hostApplicationBuilder.Build());
return this._builtApplication;
}

​ 篇幅问题这里不展开讨论,但在Build方法中会有四个钩子被执行

public IHostBuilder ConfigureHostConfiguration(Action<IConfigurationBuilder> configureDelegate)
public IHostBuilder ConfigureAppConfiguration(Action<HostBuilderContext, IConfigurationBuilder> configureDelegate)
public IHostBuilder ConfigureServices(Action<HostBuilderContext, IServiceCollection> configureDelegate)
public IHostBuilder ConfigureContainer<TContainerBuilder>(Action<HostBuilderContext, TContainerBuilder> configureDelegate)

​ 最终服务容器会被标记成只读

IEndpointRouteBuilder

IEndpointRouteBuilder为程序定义路由构建的约定。

ICollection<EndpointDataSource> DataSources { get; }

​ 这是 WebApplication 中的实现,可以看到 EndpointDataSource 的实现会被组合进来。

public IReadOnlyList<Endpoint> Endpoints
{
get
{
EndpointDataSource requiredService = this._webApplication.Services.GetRequiredService<EndpointDataSource>();
return requiredService is CompositeEndpointDataSource endpointDataSource && endpointDataSource.DataSources.Intersect<EndpointDataSource>((IEnumerable<EndpointDataSource>) this._webApplication.DataSources).Count<EndpointDataSource>() != this._webApplication.DataSources.Count ? new CompositeEndpointDataSource((IEnumerable<EndpointDataSource>) this._webApplication.DataSources).Endpoints : requiredService.Endpoints;
}
}

EndpointDataSource实际上就是一组 Endpoint,而 Endpoint 是 AspNetCore 下极其重要的一节,同样会在后续展开讲。现在你只需要知道,它表示一个处理 HTTP 请求的终点,包含了处理请求的逻辑和相关的元数据。

IAsyncDisposable

IAsyncDisposable 是 .NET Core 2.0 引入的一个接口,用于异步释放资源的模式。它是 IDisposable 接口的异步版本。某些资源的释放可能涉及到异步操作,使用 IDisposable 接口的同步释放模式可能会导致阻塞线程,影响应用程序的性能和响应性。

public interface IAsyncDisposable
{
ValueTask DisposeAsync();
}

​ 在使用完该对象后,可以使用 await using语法糖或直接调用 ``DisposeAsync()` 方法来释放资源。

Run

Run 函数是 WebApplication 的启动按钮,你可以传递一个url,加入到监听列表

public void Run([StringSyntax("Uri")] string? url = null)
{
this.Listen(url);
// public static void Run(this IHost host) => host.RunAsync().GetAwaiter().GetResult();
HostingAbstractionsHostExtensions.Run(this);
}

HostingAbstractionsHostExtensions.Run的源码相对简单,host的 StartAsyncWaitForShutdownAsync 在上面都介绍了,WebApplicationDisposeAsync 也在finally块中触发

public static async Task RunAsync(this IHost host, CancellationToken token = default (CancellationToken))
{
try
{
ConfiguredTaskAwaitable configuredTaskAwaitable = host.StartAsync(token).ConfigureAwait(false);
await configuredTaskAwaitable;
configuredTaskAwaitable = host.WaitForShutdownAsync(token).ConfigureAwait(false);
await configuredTaskAwaitable;
}
finally
{
if (host is IAsyncDisposable asyncDisposable)
await asyncDisposable.DisposeAsync().ConfigureAwait(false);
else
host.Dispose();
}
}

​ 上面有个很有意思的点是,为什么要在finally块中触发?这是因为Host的生命周期函数都用了联合取消令牌,这是一种安全取消协作模式,在令牌取消后会触发一个 OperationCanceledException 异常,进而在这种情况下还能够正常处理销毁工作,这是一种非常优秀的编程习惯。

.NET8 WebApplication剖析的更多相关文章

  1. 探索C#之6.0语法糖剖析

    阅读目录: 自动属性默认初始化 自动只读属性默认初始化 表达式为主体的函数 表达式为主体的属性(赋值) 静态类导入 Null条件运算符 字符串格式化 索引初始化 异常过滤器when catch和fin ...

  2. jQuery之Deferred源码剖析

    一.前言 大约在夏季,我们谈过ES6的Promise(详见here),其实在ES6前jQuery早就有了Promise,也就是我们所知道的Deferred对象,宗旨当然也和ES6的Promise一样, ...

  3. [C#] 剖析 AssemblyInfo.cs - 了解常用的特性 Attribute

    剖析 AssemblyInfo.cs - 了解常用的特性 Attribute [博主]反骨仔 [原文]http://www.cnblogs.com/liqingwen/p/5944391.html 序 ...

  4. Membership三步曲之进阶篇 - 深入剖析Provider Model

    Membership 三步曲之进阶篇 - 深入剖析Provider Model 本文的目标是让每一个人都知道Provider Model 是什么,并且能灵活的在自己的项目中使用它. Membershi ...

  5. 《AngularJS深度剖析与最佳实践》简介

    由于年末将至,前阵子一直忙于工作的事务,不得已暂停了微信订阅号的更新,我将会在后续的时间里尽快的继续为大家推送更多的博文.毕竟一个人的力量微薄,精力有限,希望大家能理解,仍然能一如既往的关注和支持sh ...

  6. 探索c#之Async、Await剖析

    阅读目录: 基本介绍 基本原理剖析 内部实现剖析 重点注意的地方 总结 基本介绍 Async.Await是net4.x新增的异步编程方式,其目的是为了简化异步程序编写,和之前APM方式简单对比如下. ...

  7. ASP.NET Core管道深度剖析(2):创建一个“迷你版”的管道来模拟真实管道请求处理流程

    从<ASP.NET Core管道深度剖析(1):采用管道处理HTTP请求>我们知道ASP.NET Core请求处理管道由一个服务器和一组有序的中间件组成,所以从总体设计来讲是非常简单的,但 ...

  8. [C#] 走进异步编程的世界 - 剖析异步方法(上)

    走进异步编程的世界 - 剖析异步方法(上) 序 这是上篇<走进异步编程的世界 - 开始接触 async/await 异步编程>(入门)的第二章内容,主要是与大家共同深入探讨下异步方法. 本 ...

  9. [C#] 走进异步编程的世界 - 剖析异步方法(下)

    走进异步编程的世界 - 剖析异步方法(下) 序 感谢大家的支持,这是昨天发布<走进异步编程的世界 - 剖析异步方法(上)>的补充篇. 目录 异常处理 在调用方法中同步等待任务 在异步方法中 ...

  10. 计算机程序的思维逻辑 (29) - 剖析String

    上节介绍了单个字符的封装类Character,本节介绍字符串类.字符串操作大概是计算机程序中最常见的操作了,Java中表示字符串的类是String,本节就来详细介绍String. 字符串的基本使用是比 ...

随机推荐

  1. MyBatis(RowBounds)分页了解内容

    RowBounds 不在使用SQL实现分页 1.接口 List<User> getUserByRowBounds(); 2.mapper.xml <select id="g ...

  2. grafana Variables 变量的使用

    概念澄清 A variable is a placeholder for a value. # 变量是值的占位符. # 参考文档:https://grafana.com/docs/grafana/la ...

  3. DNS与CDN技术

    参考链接: CDN原理简单介绍 浅析:DNS解析和CDN加速 DNS报文格式解析

  4. AttributeError:module‘win32com.gen_py has no attribute ‘CLSIDToClassMap‘

    解决方案如下: 1. 运行如下代码,找到文件所在位置 from win32com.client.gencache import EnsureDispatch import sys xl = Ensur ...

  5. 论文解读(MCD)《Maximum Classifier Discrepancy for Unsupervised Domain Adaptation》

    Note:[ wechat:Y466551 | 付费咨询,非诚勿扰 ] 论文信息 论文标题:Maximum Classifier Discrepancy for Unsupervised Domain ...

  6. GitOps 与 DevOps:了解关键差异,为企业做出最佳选择

    在软件开发领域,GitOps 和 DevOps 是加强协作和实现软件交付流程自动化的重要技术.虽然这两种模式都旨在提高软件开发生命周期的效率,但它们的核心原则和实施方式却各不相同. 本篇文章将帮助您了 ...

  7. 「AntV」x6 框选添加右键菜单

    今天在群里有个小伙伴提出了这么个问题:如何在框选完成后给框选的区域添加一个右键菜单的功能,我看到了这个问题后也是有点懵,心里想着怎么还有这个需求,直接快捷键删除不是更好吗,谁知这位小伙伴也是这么写的, ...

  8. 零代码,使用 Dify 和 Laf 两分钟接入企业微信 AI 机器人

    Dify 允许创建 AI 应用,并提供二次开发的能力.这里我将演示创建一个法律问答助手的 AI 应用,称作"知法".在本篇教程中,我将指导你为"知法"接入企业微 ...

  9. 《小白WEB安全入门》03. 漏洞篇

    @ 目录 SQL注入和简单绕过原理 什么是SQL 什么是SQL注入 XSS漏洞原理 什么是XSS XSS分类 NOSQL注入 什么是NOSQL CSRF原理 什么是CSRF 网络摄像头入侵原理 什么是 ...

  10. 如何使用io_uring构建快速响应的I/O密集型应用?

    本文分享自华为云社区<如何使用io_uring构建快速响应的I/O密集型应用>,作者: Lion Long . 当涉及构建快速响应的I/O密集型应用时,io_uring技术展现出了其卓越的 ...