.NET8 WebApplication剖析

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 异常,进而在这种情况下还能够正常处理销毁工作,这是一种非常优秀的编程习惯。

发表评论

评论已关闭。

相关文章