asp.net core 3.x Endpoint终结点路由1-基本介绍和使用

前言

我是从.net 4.5直接跳到.net core 3.x的,感受asp.net这套东西最初是从4.5中的owin造成的。
目前官方文档重点是讲路由,没有特别说明与传统路由的区别,本篇主要介绍终结点路由的相关概念和如何使用,不会详细介绍路由,这个参考官方文档就ok了。若是未来有机会研究到底层再深度剖析。web

参考:
https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/routing?view=aspnetcore-3.1
https://q.cnblogs.com/q/113644/ 
https://aregcode.com/blog/2019/dotnetcore-understanding-aspnet-endpoint-routing/api

概述

最初咱们访问 http://www.abc.com/a.aspx时,服务端是存在a.aspx这个文件的,服务端根据此文件帮咱们建立一个对应类的实例处理请求。
后来需求愈来愈复杂,出现了路由,目的是将请求地址与执行请求的处理器的直接关联,变成映射关联,映射规则由咱们本身配置。
在asp.net core 3.x以前这个路由系统是包含在mvc内部的,.net framework时代有个特殊的HttpModule来实现mvc,路由系统也包含其中。.net core是由有个特殊的中间件来实现mvc的,路由系统就包含在这个中间件中。
这种方式有个问题,mvc只是一个中间件,路由系统包含在其中,若是咱们但愿在mvc中间件以后加入其它中间件,其它中间件是没法(也许是不方便)访问路由相关信息的。
另外asp.net core并非只有mvc,还有webapi、blazor、signlR、接入gRpc等,未来还有更多,咱们的路由系统可否提出来,让全部框架均可以用?mvc

所以出现了终结点路由,咱们说路由的根本目的是将用户请求地址,映射为一个请求处理器,最简单的请求处理器能够是一个委托 Func<HttpCotnext,Task>,也能够是mvc/webapi中某个controller的某个action,因此从抽象的角度讲 一个终结点 就是一个处理请求的委托。因为mvc中action上还有不少attribute,所以咱们的终结点还应该提供一个集合,用来存储与此请求处理委托的关联数据。
从抽象的角度能够简单理解为   一个终结点 = 处理请求的委托 + 与之关联的附加(元)数据。对应到mvc来理解的话 终结点 = action + 应用其上的attribute集合。但记住终结点是个抽象的概念,并不仅服务于mvc,原理大概以下:app

  1. 在程序启动前咱们应该定义好程序中有哪些终结点,固然不是咱们手动一个个定义,而是根据目标框架自动生成,针对mvc来讲的话能够自动将程序中与路由匹配的action转换成对应的终结点,其它框架应该也有对应的方式,反正最终咱们全部用来处理请求的东东都变成了终结点。这步是在定义路由时自动完成的
  2. 除了定义终结点咱们还要定义 请求路径 与 终结点的对应关系,未来请求抵达时才能匹配找到合适的终结点来处理咱们的请求,这步至关于定义路由
  3. 咱们还须要定义一个解析器,当请求抵达时根据终结点与路径的对应关系找到终结点,微软已定义好对应的中间件来表示这个解析器。
  4. 最后咱们须要定义一个中间件,在上面的中间件执行后 咱们能够拿到与当前请求匹配的终结点,最终调用它的委托处理请求,这个中间件就是mvc中间件
  5. 到此asp.net core 3.x的中间件路由默认差很少就这样了,此时咱们能够定义本身的中间件,放在步骤3后面,拿到终结点作一些高级处理。微软定义的一些中间件也是这个套路

如何使用

在经过vs默认模板建立asp.net core 3.x项目时,在startup中会看到这样的代码框架

1 app.UseRouting();
2 app.UseEndpoints(endpoints => {
3   endpoints.MapControllerRoute(
4     name: "default",
5     pattern: "{controller=Home}/{action=Index}/{id?}");
6 });

注册路由

看代码的第2行。它有以下3个任务asp.net

  1. 建立终结点定义,针对mvc来讲会自动将程序中与路由格式匹配上的action转换为终结点。在第5行以后能够调试观察endpoints.DataSource属性,生成好的终结点就在里面
  2. 创建url与终结点的对应关系,这种关系存在哪?我也不晓得
  3. 注册mvc中间件(它在未来请求抵达,且以前有中间件解析获得与当前请求匹配的终结点后,开始mvc旅程)

这里路由跟之前的写法差很少,上面默认值啊、约束啊就去看官方文档吧。
建立终结点也会参照属性路由,微软推荐webapi使用属性路由,mvc使用传统路由。你会看到建立默认webapi项目时这样的 endpoints.MapControllers(); ide

终结点进一步定制

默认状况下是根据定义的路由去找到匹配的action最后生成终结点,这个生成终结点的过程咱们是能够参与的,具体办法是经过endpoints.MapControllerRoute的返回对象上调用相关扩展方法,本质上是向终结点的建立过程加入一些委托,未来建立终结点时,这些委托将被调用,代码以下:ui

1 endpoints.MapControllerRoute(
2                     name: "default",
3                     pattern: "{controller=Home}/{action=Index}/{id?}").Add(endpointBuilder=> {
4                         //经过endpointBuilder获取与action关联的数据,好比attribute和其它元数据
5                         //经过endpointBuilder插入咱们向放进终结点的数据
6                     });

动态路由

app.UseEndpointsmvc时就说明了使用mvc和webapi了,默认状况下一个action会建立一个对应的终结点,请求抵达时匹配到终结点就直接执行了。但有时候咱们但愿本身控制一个请求过来时使用哪一个controller的哪一个action,具体作法:
定义一个类,继承DynamicRouteValueTransformer,并注册到ioc容器中,最后调用一个扩展方法,看代码:url

 1     class MyRouteValueTransformer : DynamicRouteValueTransformer
 2     {
 3         public override ValueTask<RouteValueDictionary> TransformAsync(HttpContext httpContext, RouteValueDictionary values)
 4         {
 5             //经过values能够拿到原始路由数据
 6             //能够替换或加入新的数据
 7             values.Add("controller", "jj");
 8             values.Add("action", "kkk");
 9             return new ValueTask<RouteValueDictionary>(values);
10         }
11     }
12 
13 public void ConfigureServices(IServiceCollection services)
14         {
15             services.AddSingleton<MyRouteValueTransformer>();
16             services.AddControllers();
17         }
18 
19 endpoints.MapDynamicControllerRoute<MyRouteValueTransformer>("aaa/bbb/{id}");

这样未来请求抵达时,解析获得终结点时会调用咱们的MyRouteValueTransformer,咱们能够获取已解析获得的路有数据,而后选择替换/增长某些路由数据,从而达到定制化spa

 

回退路由

默认状况下请求抵达时,若没有找到匹配的终结点,就直接404了,咱们但愿当没有匹配到任何终结点时直接执行某个默认的终结点,能够用以下方式:

endpoints.MapFallbackToController("{controller}/{action}/{id?}", "kkk", "jj");

当请求抵达时,若是没有匹配到任何终结点,则默认执行jjController.kkk方法。能够想象获得此功能多是经过动态路由实现的

还有几个相关的扩展方法,有了上面的讲解,估计你也能猜出是干吗用的了。关于路由注册就暂时说这么多

 

自定义中间件提早拿到终结点数据

app.UseRouting();对应概述中的步骤3,此扩展方法内部会注册一个中间件,未来请求抵达时它会帮咱们找到与当前请求匹配的终结点并存储在HttpContext中,且匹配过程当中解析获得的路由数据在Request.RouteValues中。咱们能够在它后面加入本身的中间件

1 app.UseRouting();
2 app.Use((conttext,next)=> {
3       var endpoint = conttext.GetEndpoint();//拿到终结点
4       var routeData = conttext.Request.RouteValues;//拿到路由数据
     //作些牛B的事
5 return next(); 6 });
相关文章
相关标签/搜索