经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » ASP.net » 查看文章
.NET8 WebApplication剖析
来源:cnblogs  作者:xiaolipro  时间:2023/11/6 9:12:01  对本文有异议

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

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

IHost

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

  1. public interface IHost : IDisposable
  2. {
  3. IServiceProvider Services { get; }
  4. Task StartAsync(CancellationToken cancellationToken = default (CancellationToken));
  5. Task StopAsync(CancellationToken cancellationToken = default (CancellationToken));
  6. }

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

? Host StartAsync 代码流如下:

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

? StopAsync 类似,代码流如下:

  1. IHostedLifecycleService.StoppingAsync
  2. IHostedService.StopAsync
  3. IHostedLifecycleService.StoppedAsync
  4. this._logger.StoppedWithException((Exception) ex);

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

IApplicationBuilder

? WebApplication 实现 IApplicationBuilder 具有pipeline机制。

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

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

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

  1. public WebApplication Build()
  2. {
  3. this._hostApplicationBuilder.Services.Add(this._genericWebHostServiceDescriptor);
  4. this.Host.ApplyServiceProviderFactory(this._hostApplicationBuilder);
  5. this._builtApplication = new WebApplication(this._hostApplicationBuilder.Build());
  6. return this._builtApplication;
  7. }

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

  1. public IHostBuilder ConfigureHostConfiguration(Action<IConfigurationBuilder> configureDelegate)
  2. public IHostBuilder ConfigureAppConfiguration(Action<HostBuilderContext, IConfigurationBuilder> configureDelegate)
  3. public IHostBuilder ConfigureServices(Action<HostBuilderContext, IServiceCollection> configureDelegate)
  4. public IHostBuilder ConfigureContainer<TContainerBuilder>(Action<HostBuilderContext, TContainerBuilder> configureDelegate)

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

IEndpointRouteBuilder

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

  1. ICollection<EndpointDataSource> DataSources { get; }

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

  1. public IReadOnlyList<Endpoint> Endpoints
  2. {
  3. get
  4. {
  5. EndpointDataSource requiredService = this._webApplication.Services.GetRequiredService<EndpointDataSource>();
  6. 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;
  7. }
  8. }

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

IAsyncDisposable

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

  1. public interface IAsyncDisposable
  2. {
  3. ValueTask DisposeAsync();
  4. }

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

Run

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

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

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

  1. public static async Task RunAsync(this IHost host, CancellationToken token = default (CancellationToken))
  2. {
  3. try
  4. {
  5. ConfiguredTaskAwaitable configuredTaskAwaitable = host.StartAsync(token).ConfigureAwait(false);
  6. await configuredTaskAwaitable;
  7. configuredTaskAwaitable = host.WaitForShutdownAsync(token).ConfigureAwait(false);
  8. await configuredTaskAwaitable;
  9. }
  10. finally
  11. {
  12. if (host is IAsyncDisposable asyncDisposable)
  13. await asyncDisposable.DisposeAsync().ConfigureAwait(false);
  14. else
  15. host.Dispose();
  16. }
  17. }

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

原文链接:https://www.cnblogs.com/xiaolipro/p/17810161.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号