• .NET 8 IEndpointRouteBuilder详解


    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 ,该方法是诸如 MapGetMapPostMapPutMapDeleteMapPatchMapMethods 的底层方法:

    ​ 他的实现就是为了给IEndpointRouteBuilderDataSources 添加一个 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 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集合,包含描述、标签、权限等数据,这一般是框架用到的,后面会再次见到它。重点是 RequestDelegateHttpContext 首次登场,相信有过Web开发经验的同学熟悉的不能再熟悉。该委托其实就是一个Func,用于处理HTTP请求,由于TAP的普及,所以返回的Task

    public delegate Task RequestDelegate(HttpContext context);
    

    Endpoint 一般由 EndpointBuilder 构建,他能够额外组装Filter

    public IList> FilterFactories
    

    EndpointDataSource

    ​ 经过对 MapGet 的剖析我们最终发现,所有的终结点都被挂载在了 EndpointDataSource

    public abstract IReadOnlyList Endpoints { get; }
    public virtual IReadOnlyList GetGroupedEndpoints(RouteGroupContext context)
    

    ​ 除了被大家熟悉的 Endpoints 还提供了一个方法 GetGroupedEndpoints:在给定指定前缀和约定的情况下,获取此EndpointDataSource 的所有 Endpoint的。

    public virtual IReadOnlyList GetGroupedEndpoints(RouteGroupContext context)
    {
    	IReadOnlyList 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 convention in context.Conventions)
    		{
    			convention(routeEndpointBuilder);
    		}
    		foreach (object metadatum in routeEndpoint.Metadata)
    		{
    			routeEndpointBuilder.Metadata.Add(metadatum);
    		}
    		foreach (Action finallyConvention in context.FinallyConventions)
    		{
    			finallyConvention(routeEndpointBuilder);
    		}
    		array[i] = (RouteEndpoint)routeEndpointBuilder.Build();
    	}
    	return array;
    }
    

    ​ 通过剖析 RouteGroupContext,很容易发觉,Prefix 是一个路由前缀,ConventionsFinallyConventions 是两个约定hook。它专为 RouteEndpoint 独有,通过 GetGroupedEndpoints 方法,组的前缀和约定,会作用到每一个路由终结点。

    public sealed class RouteGroupContext
    {
        public required RoutePattern Prefix { get; init; }
        public IReadOnlyList> Conventions { get; init; } = Array.Empty>();
        public IReadOnlyList> FinallyConventions { get; init; } = Array.Empty>();
    }
    
  • 相关阅读:
    OpenGL之着色器
    OOM和JVM最详细介绍
    nvm安装及使用,nodejs版本切换使用
    Docker | redis安装及测试
    【elasticsearch】搜索过程详解
    CSS---flex布局
    LeetCode 26. 删除有序数组中的重复项
    关于网络连接的一些易忘点-HTTP/TCP/UDP
    使用 Django 构建简单 Web 应用
    图信号处理论文
  • 原文地址:https://www.cnblogs.com/xiaolipro/p/17818017.html