• .NET8 WebApplication剖析


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

    /// 
    /// The web application used to configure the HTTP pipeline, and routes.
    /// 
    [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()?.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 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 configureDelegate)
    public IHostBuilder ConfigureAppConfiguration(Action configureDelegate)
    public IHostBuilder ConfigureServices(Action configureDelegate)
    public IHostBuilder ConfigureContainer(Action configureDelegate)
    

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

    IEndpointRouteBuilder

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

    ICollection DataSources { get; }
    

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

    public IReadOnlyList Endpoints
    {
      get
      {
        EndpointDataSource requiredService = this._webApplication.Services.GetRequiredService();
        return requiredService is CompositeEndpointDataSource endpointDataSource && endpointDataSource.DataSources.Intersect((IEnumerable) this._webApplication.DataSources).Count() != this._webApplication.DataSources.Count ? new CompositeEndpointDataSource((IEnumerable) 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 异常,进而在这种情况下还能够正常处理销毁工作,这是一种非常优秀的编程习惯。

  • 相关阅读:
    【elasticsearch实战】从零开始设计全站搜索引擎
    【数据处理】建立数据库索引并定时重建索引
    简易步骤控制器
    OpenMV与JSON编码
    MySQL-MySQL数据类型
    hive分区表新增字段CASCADE有无区别
    力扣刷题学习SQL篇——1-3 选择(从不订购的客户——使用not in)
    [Windows Server 2019] 安装与配置邮件服务器
    JS-对象 - 1
    任职超18年,Go团队技术主管Russ Cox官宣卸任!
  • 原文地址:https://www.cnblogs.com/xiaolipro/p/17810161.html