路由
分类: Asp.net Core入门 ◆ 标签: #Asp.Net core基础 #基础 #Web ◆ 发布于: 2023-06-04 20:37:05

关于路由这个部分,我想有几个技术要点是需要先理解清楚的,否则的话,可能很多新手同学对于理解Asp.net Core
3.0之后的以中间件: UseRouting
和UseEndpoint
这个两个概念可能会非常混淆,可能非常不明白为什么既然有了路由的中间件,为什么还需要Endpoint这样一个中间件。
先说为什么?我理解最主要的就是为了解耦,将路由匹配,路径选择这些功能和选择好路由之后实际执行完全分开,也就是如果你愿意,你完全可以自己重新定义路由组件,但是不影响Endpoint中间件的执行。
另外要理解的是我们在Startup
的Configure
方法中执行的扩展方法,都是在注册将来要在一个request里执行的委托,也就是在该方法里前后执行的顺序并不影响将来在request里执行的顺序,为什么要理解这个呢?这是因为我们发现我们使用了UseRoute
注册了路由中间件之后,并没有对Endpoint进行匹配,实际的匹配反而是在UseEndpoint中通过Endpoint
的扩展方法来匹配的。
第三点重要的理解,实际上路由就是根据路径和header来进行路由的,这个其实是不变的基本原理。
第四点,就是Endpoint本身概念的理解,我们在Endpoint
上实际已经赋予了很多概念,例如有赋予利用一些数据进行定义的规则。例如认证等等。
第五点我们需要注意一个请求在所有的这些中间件进行流动的时候,实际上是有一个对象来表示这个请求的,这就是HttpContext
下面我们来快速的做一下学习记录。
什么是Endpoint
Endpoint是一个抽象的可执行的单位,也就是除了要给出一个怎么和路由匹配的规则,同时还要给出一个匹配了这个规则之后的可以执行的RequestDelte
, 关于这个委托,我们可以快速的看一下定义:
public delegate System.Threading.Tasks.Task RequestDelegate(HttpContext context);
可以看到这个委托里唯一个参数就是封装好的http上下文。
同时我们在Endpoint
可以使用很多种方法来匹配路由规则,例如:
- MapGet
- MapPost
- Map
- MapDelete
- MapPut
- MapMethod
等等,看看这些方法的定义,基本都是扩展方法,例如:
public static Microsoft.AspNetCore.Builder.IEndpointConventionBuilder MapGet (this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints, string pattern, Microsoft.AspNetCore.Http.RequestDelegate requestDelegate);
就可以看到这个方法是IEndpointRouteBuilder
的扩展方法,然后是一个字符串定义的模式,最后是一个可以执行的委托,使用方法如下:
app.UseEndpoints(endpoints => { endpoints.MapGet("/hello/{name:alpha}", async context => { var name = context.Request.RouteValues["name"]; await context.Response.WriteAsync($"Hello {name}!"); }); });
实际上一个endpoint定义了:
- 一个用来执行的委托。
- metadata的集合。MetaData非常有用处,及其适合用于切面编程。例如在userouting和useendpoint中间添加其他的处理方式,
可以以下面这个例子理解一下:
public class IntegratedMiddlewareStartup { public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } // Location 1: Before routing runs. Can influence request before routing runs. app.UseHttpMethodOverride(); app.UseRouting(); // Location 2: After routing runs. Middleware can match based on metadata. app.Use(next => context => { var endpoint = context.GetEndpoint(); if (endpoint?.Metadata.GetMetadata<AuditPolicyAttribute>()?.NeedsAudit == true) { Console.WriteLine($"ACCESS TO SENSITIVE DATA AT: {DateTime.UtcNow}"); } return next(context); }); app.UseEndpoints(endpoints => { endpoints.MapGet("/", async context => { await context.Response.WriteAsync("Hello world!"); }); // Using metadata to configure the audit policy. endpoints.MapGet("/sensitive", async context => { await context.Response.WriteAsync("sensitive data"); }) .WithMetadata(new AuditPolicyAttribute(needsAudit: true)); }); } } public class AuditPolicyAttribute : Attribute { public AuditPolicyAttribute(bool needsAudit) { NeedsAudit = needsAudit; } public bool NeedsAudit { get; } }
可以从这个例子里看到中间件,以及routting和endpoint之间是怎么交互的。
更为详细的内容,我们后面在学习Razor page
和MVC
的时候再来学习。
请认真理解一下者两个中间件的设计。