.NET8 WebApplication剖析

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

c# 复制代码
/// <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 就是程序的抽象

c# 复制代码
public interface IHost : IDisposable
{
  IServiceProvider Services { get; }
  Task StartAsync(CancellationToken cancellationToken = default (CancellationToken));
  Task StopAsync(CancellationToken cancellationToken = default (CancellationToken));
}

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

​ Host StartAsync 代码流如下:

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

StopAsync 类似,代码流如下:

c# 复制代码
IHostedLifecycleService.StoppingAsync
IHostedService.StopAsync
IHostedLifecycleService.StoppedAsync
this._logger.StoppedWithException((Exception) ex);

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

IApplicationBuilder

WebApplication 实现 IApplicationBuilder 具有pipeline机制。

c# 复制代码
IApplicationBuilder Use(Func<RequestDelegate, RequestDelegate> middleware);
RequestDelegate Build();

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

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

c# 复制代码
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方法中会有四个钩子被执行

c# 复制代码
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为程序定义路由构建的约定。

c# 复制代码
ICollection<EndpointDataSource> DataSources { get; }

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

c# 复制代码
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 接口的同步释放模式可能会导致阻塞线程,影响应用程序的性能和响应性。

c# 复制代码
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块中触发

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

相关推荐
棉晗榜6 天前
.net core在linux导出excel,System.Drawing.Common is not supported on this platform
linux·excel·asp.net core·miniexcel
棉晗榜6 天前
asp.net core发布配置端口号,支持linux
asp.net core
coredx8 天前
如何优雅地让 ASP.NET Core 支持异步模型验证
asp.net core
小乖兽技术16 天前
ASP.NET Core Web 项目的部署:选择 IIS 还是 Kestrel?
后端·kestrel·iis·asp.net·asp.net core
界面开发小八哥18 天前
DevExtreme JS & ASP.NET Core v24.2新功能预览 - 全新的聊天组件
javascript·ui·asp.net core·界面控件·ui开发·devextreme·.net 9
gc_229922 天前
学习ASP.NET Core的身份认证(基于Session的身份认证3)
asp.net core·session·身份认证
gc_229924 天前
ASP.NET Core项目中使用SqlSugar连接多个数据库的方式
asp.net core·sqlsugar·多数据库
gc_229925 天前
学习ASP.NET Core的身份认证(基于Session的身份认证1)
asp.net core·session·身份认证
gc_22991 个月前
学习ASP.NET Core的身份认证(基于Cookie的身份认证1)
asp.net core·cookie·身份认证
gc_22991 个月前
学习ASP.NET Core的身份认证(基于Cookie的身份认证3)
asp.net core·cookie·身份认证