.NET 8 IApplicationBuilder详解

在上节中我们已经得知 WebApplication 实现了 IApplicationBuilder,我们浅谈了其pipe特质和构建方法,本节中将深入了解 ApplicationBuilder 以窥探 IApplicationBuilder 真相

public interface IApplicationBuilder
{
    IServiceProvider ApplicationServices { get; set; }
    IFeatureCollection ServerFeatures { get; }
    IDictionary<string, object?> Properties { get; }
    IApplicationBuilder Use(Func<RequestDelegate, RequestDelegate> middleware);
    IApplicationBuilder New();
    RequestDelegate Build();
}

管道机制

​ 该机制是.NET最关键的机制之一,贯彻整个APP生命周期,但他的实现,简单巧妙的让人惊叹。

​ 首先在内部维护了一个 Func<RequestDelegate, RequestDelegate> 集合

private readonly List<Func<RequestDelegate, RequestDelegate>> _components = new List<Func<RequestDelegate, RequestDelegate>>();

Func<RequestDelegate, RequestDelegate> 还有一个美腻的别名叫:中间件,UseMiddleware 的本质,就是 IApplicationBuilder.Use,调用 Use 其实就是添加一个中间件到集合

public IApplicationBuilder Use(Func<RequestDelegate, RequestDelegate> middleware)
{
  this._components.Add(middleware);
  return (IApplicationBuilder) this;
}

​ 最终在 Build 生成此应用程序用于处理HTTP请求的委托。

public RequestDelegate Build()
{
  RequestDelegate requestDelegate = (RequestDelegate) (context =>
  {
    Endpoint endpoint = context.GetEndpoint();
    if (endpoint?.RequestDelegate != null)
      throw new InvalidOperationException("The request reached the end of the pipeline without executing the endpoint: '" + endpoint.DisplayName + "'. Please register the EndpointMiddleware using 'IApplicationBuilder.UseEndpoints(...)' if using routing.");
    context.Response.StatusCode = 404;
    return Task.CompletedTask;
  });
  for (int index = this._components.Count - 1; index >= 0; --index)
    requestDelegate = this._components[index](requestDelegate);
  return requestDelegate;
}

​ 为什么要倒着循环呢?这是因为在ASP.NET Core中,中间件的执行顺序是按照它们在ApplicationBuilder中注册的顺序来决定的。后注册的中间件会在前注册的中间件之前执行,这就是经典的洋葱模型

Properties&Features

Properties 是一个字典,用于在中间件之间共享数据。

public IDictionary<string, object?> Properties { get; }

​ 为了防止在中间件中修改 ApplicationBuilder 对象的状态,实现了一个原型模型:仅复制 Properties

public IApplicationBuilder New() => (IApplicationBuilder) new ApplicationBuilder(this);
private ApplicationBuilder(ApplicationBuilder builder) => this.Properties = (IDictionary<string, object>) new CopyOnWriteDictionary<string, object>(builder.Properties, (IEqualityComparer<string>) StringComparer.Ordinal);

Features 用于获取应用程序Server提供的一组HTTP features,如果程序没有指定Server,则返回空集合

public interface IFeatureCollection : IEnumerable<KeyValuePair<Type, object>>, IEnumerable

​ 在 ApplicationBuilderFeatures 直接引用 Properties,他们两者基本等价。而在 WebApplication 中,通过 IServer 提供

IFeatureCollection ServerFeatures => this._host.Services.GetRequiredService<IServer>().Features;

IServer 是服务器知识,看同学们述求,考虑是否讲

IServiceProvider

IServiceProvider 用于访问应用程序服务容器,位于 System 命名空间,在整个 .NET 中举重若轻。它的功能非常简洁,只做一件事情,仅有一个方法,用于从服务容器中获取给定服务的实现

public interface IServiceProvider
{
  /// <summary>Gets the service object of the specified type.</summary>
  /// <param name="serviceType">An object that specifies the type of service object to get.</param>
  /// <returns>A service object of type <paramref name="serviceType" />.
  /// -or-
  /// <see langword="null" /> if there is no service object of type <paramref name="serviceType" />.</returns>
  object? GetService(Type serviceType);
}

​ 服务容器化,横空出世;依赖注入,孕育而生

posted @ 2023-11-07 20:05  xiaolipro  阅读(445)  评论(0编辑  收藏  举报