Map
经过对 WebApplication 的初步剖析,我们已经大致对 Web 应用的骨架有了一定了解,现在我们来看一下 Hello World 案例中仅剩的一条代码:
app.MapGet("/", () => "Hello World!"); // 3 添加路由处理
复制代码
老规矩,看签名:
public static RouteHandlerBuilder MapGet(this IEndpointRouteBuilder endpoints, [StringSyntax("Route")] string pattern,Delegate handler){ return endpoints.MapMethods(pattern, (IEnumerable<string>) EndpointRouteBuilderExtensions.GetVerb, handler);}
复制代码
我们已经解释过 IEndpointRouteBuilder 的定义了,即为程序定义路由构建的约定。这次看到的是他的拓展方法 Map ,该方法是诸如 MapGet、MapPost、MapPut、MapDelete、MapPatch、MapMethods 的底层方法:
他的实现就是为了给IEndpointRouteBuilder 的 DataSources 添加一个 RouteEndpointDataSource
private static RouteHandlerBuilder Map(this IEndpointRouteBuilder endpoints, RoutePattern pattern, Delegate handler, IEnumerable<string> httpMethods, bool isFallback){ return endpoints.GetOrAddRouteEndpointDataSource().AddRouteHandler(pattern, handler, httpMethods, isFallback, RequestDelegateFactory.InferMetadata, RequestDelegateFactory.Create);}
复制代码
RouteEndpointDataSource 继承自 EndpointDataSource,提供一组RouteEndpoint
public override IReadOnlyList<RouteEndpoint> Endpoints{ get { RouteEndpoint[] array = new RouteEndpoint[_routeEntries.Count]; for (int i = 0; i < _routeEntries.Count; i++) { array[i] = (RouteEndpoint)CreateRouteEndpointBuilder(_routeEntries[i]).Build(); } return array; }}
复制代码
Endpoint
RouteEndpoint 继承自 Endpoint。多了一个 RoutePattern 属性,用于路由匹配,支持模式路由。还有一个 Order 属性,用于处理多匹配源下的优先级问题。
public sealed class RouteEndpoint : Endpoint{ public int Order { get; } public RoutePattern RoutePattern { get; }}
复制代码
Endpoint 是一个应用程序中路的一个逻辑终结点。
public string? DisplayName { get; } // 终结点名称public EndpointMetadataCollection Metadata { get; } // 元数据public RequestDelegate? RequestDelegate { get; } // 请求委托
复制代码
其中 Metadata 就是一个 object 集合,包含描述、标签、权限等数据,这一般是框架用到的,后面会再次见到它。重点是 RequestDelegate:HttpContext 首次登场,相信有过 Web 开发经验的同学熟悉的不能再熟悉。该委托其实就是一个Func<HttpContext, Task>,用于处理 HTTP 请求,由于 TAP 的普及,所以返回的Task。
public delegate Task RequestDelegate(HttpContext context);
复制代码
Endpoint 一般由 EndpointBuilder 构建,他能够额外组装 Filter
public IList<Func<EndpointFilterFactoryContext, EndpointFilterDelegate, EndpointFilterDelegate>> FilterFactories
复制代码
EndpointDataSource
经过对 MapGet 的剖析我们最终发现,所有的终结点都被挂载在了 EndpointDataSource
public abstract IReadOnlyList<Endpoint> Endpoints { get; }public virtual IReadOnlyList<Endpoint> GetGroupedEndpoints(RouteGroupContext context)
复制代码
除了被大家熟悉的 Endpoints 还提供了一个方法 GetGroupedEndpoints:在给定指定前缀和约定的情况下,获取此EndpointDataSource 的所有 Endpoint的。
public virtual IReadOnlyList<Endpoint> GetGroupedEndpoints(RouteGroupContext context){ IReadOnlyList<Endpoint> endpoints = Endpoints; RouteEndpoint[] array = new RouteEndpoint[endpoints.Count]; for (int i = 0; i < endpoints.Count; i++) { Endpoint endpoint = endpoints[i]; if (!(endpoint is RouteEndpoint routeEndpoint)) { throw new NotSupportedException(Resources.FormatMapGroup_CustomEndpointUnsupported(endpoint.GetType())); } RoutePattern routePattern = RoutePatternFactory.Combine(context.Prefix, routeEndpoint.RoutePattern); RouteEndpointBuilder routeEndpointBuilder = new RouteEndpointBuilder(routeEndpoint.RequestDelegate, routePattern, routeEndpoint.Order) { DisplayName = routeEndpoint.DisplayName, ApplicationServices = context.ApplicationServices }; foreach (Action<EndpointBuilder> convention in context.Conventions) { convention(routeEndpointBuilder); } foreach (object metadatum in routeEndpoint.Metadata) { routeEndpointBuilder.Metadata.Add(metadatum); } foreach (Action<EndpointBuilder> finallyConvention in context.FinallyConventions) { finallyConvention(routeEndpointBuilder); } array[i] = (RouteEndpoint)routeEndpointBuilder.Build(); } return array;}
复制代码
通过剖析 RouteGroupContext,很容易发觉,Prefix 是一个路由前缀,Conventions 和 FinallyConventions 是两个约定 hook。它专为 RouteEndpoint 独有,通过 GetGroupedEndpoints 方法,组的前缀和约定,会作用到每一个路由终结点。
public sealed class RouteGroupContext{ public required RoutePattern Prefix { get; init; } public IReadOnlyList<Action<EndpointBuilder>> Conventions { get; init; } = Array.Empty<Action<EndpointBuilder>>(); public IReadOnlyList<Action<EndpointBuilder>> FinallyConventions { get; init; } = Array.Empty<Action<EndpointBuilder>>();}
复制代码
文章转载自:xiaolipro
原文链接:https://www.cnblogs.com/xiaolipro/p/17818017.html
评论