25:路由与终结点:如何规划好你的Web API(上)-开发实战
.NET Core开发实战前文传送门:
- 第1课:课程介绍
- 第2课:内容综述
- 第3课:.NET Core的现状、未来以及环境搭建
- 第4课:Startup:掌握ASP.NET Core的启动过程
- 第5课:依赖注入:良好架构的起点(上)
- 第5课:依赖注入:良好架构的起点(中)
- 第5课:依赖注入:良好架构的起点(下)
- 第6课:作用域与对象释放行为(上)
- 第6课:作用域与对象释放行为(下)
- 第7课:用Autofac增强容器能力(上)
- 第7课:用Autofac增强容器能力(下)
- 第8课:配置框架:让服务无缝适应各种环境
- 第9课:命令行配置提供程序
- 第10课:环境变量配置提供程序
- 第11课:文件配置提供程序
- 第12课:配置变更监听
- 第13课:配置绑定:使用强类型对象承载配置数据
- 第14课:自定义配置数据源:低成本实现定制化配置方案
- 第15课:选项框架:服务组件集成配置的最佳实践
- 第16课:选项数据热更新:让服务感知配置的变化
- 第17课:为选项数据添加验证:避免错误配置的应用接收用户流量
- 第18课:日志框架:聊聊记日志的最佳姿势(上)
- 第18课:日志框架:聊聊记日志的最佳姿势(下)
- 第19课:日志作用域:解决不同请求之间的日志干扰
- 第20课:结构化日志组件Serilog:记录对查询分析友好的日志
- 第21课:中间件:掌控请求处理过程的关键(上)
- 第21课:中间件:掌控请求处理过程的关键(下)
- 第22课:异常处理中间件:区分真异常与逻辑异常(上)
- 第22课:异常处理中间件:区分真异常与逻辑异常(下)
- 第23课:静态文件中间件:前后端分离开发合并部署骚操作(上)
- 第23课:静态文件中间件:前后端分离开发合并部署骚操作(下)
- 第24课:文件提供程序:让你可以将文件放在任何地方
25 | 路由与终结点:如何规划好你的Web API
路由系统在 ASP.NET MVC 框架里面就已经存在了,在 ASP.NET Core 框架里面进行了改进
路由系统的核心作用是指 URL 和 应用程序 Controller 的对应关系的一种映射
这个映射关系实际上有两种作用:
1、把 URL 映射到对应的 Controller 对应的 action 上面去
2、根据 Controller 和 action 的名字来生产 URL
.NET Core 提供了两种路由注册的方式:
1、路由模板的方式
2、RouteAttribute 方式
这两种方式分别适用于的场景是不一样的
路由模板的方式是之前传统的方式,可以用来作为 MVC 的页面 Web 配置
现在用的比较多的前后端分离的架构,定义 Web API 的时候使用 RouteAttribute 方式去做
在定义路由,注册路由的过程中间,有一个重要的特性就是路由约束,是指路由如何匹配
有以下简单的几种约束:
1、类型约束
2、范围约束
3、正则表达式
4、是否必选
5、自定义 IRouteConstraint
另外路由系统提供了两个关键的类,用来反向根据路由的信息生产 URL 地址
1、LinkGenerator
2、IUrlHelper
IUrlHelper 与 MVC 框架里面的 MVCHelper 很像
而 LinkGenerator 是全新提供的一个链接生成的对象,可以从容器里面,在任意的位置都可以获取到这个对象,然后根据需要生成 URL 地址
接下来看一下代码
源码链接:
https://github.com/witskeeper/geektime/tree/master/samples/RoutingDemo
为了方便演示,这里先注册了一组 Swagger 的代码,将 Web API 通过 Swagger 的可视化界面输出出来
引入 Swagger 对应 ASP.NET Core 的包
Swashbuckle.AspNetCore
将代码文档 XML 文档注入给 Swagger
services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new OpenApiInfo { Title = "My API", Version = "v1" }); var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); c.IncludeXmlComments(xmlPath); });
在中间件里面注册 Swagger
app.UseSwagger(); app.UseSwaggerUI(c => { c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1"); });
这样子就可以在界面上看到 Swagger 的界面,并且浏览我们定义的 API
接着是路由的定义 OrderController
namespace RoutingDemo.Controllers { [Route("api/[controller]/[action]")]// RouteAttribute 的方式 [ApiController] public class OrderController : ControllerBase { /// <summary> /// /// </summary> /// <param name="id">必须可以转为long</param> /// <returns></returns> [HttpGet("{id:MyRouteConstraint}")]// 这里使用了自定义的约束 public bool OrderExist(object id) { return true; } /// <summary> /// /// </summary> /// <param name="id">最大20</param> /// <returns></returns> [HttpGet("{id:max(20)}")]// 这里使用了 Max 的约束 public bool Max(long id) { return true; } /// <summary> /// /// </summary> /// <param name="ss">必填</param> /// <returns></returns> [HttpGet("{name:required}")]// 必填约束 public bool Reque(string name) { return true; } /// <summary> /// /// </summary> /// <param name="number">以三个数字开始</param> /// <returns></returns> [HttpGet("{number:regex(^\\d{{3}}$)}")]// 正则表达式约束 public bool Number(string number) { return true; } } }
上面用到了自定义约束 MyRouteConstraint
namespace RoutingDemo.Constraints { public class MyRouteConstraint : IRouteConstraint { public bool Match(HttpContext httpContext, IRouter route, string routeKey, RouteValueDictionary values, RouteDirection routeDirection) { if (RouteDirection.IncomingRequest == routeDirection) { var v = values[routeKey]; if (long.TryParse(v.ToString(), out var value)) { return true; } } return false; } } }
注册 MyRouteConstraint
services.AddRouting(options => { options.ConstraintMap.Add("MyRouteConstraint", typeof(MyRouteConstraint)); });
让它生效之前,需要在中间件注册的位置注入 UseEndpoints,然后对 UseEndpoints 使用 MapControllers
app.UseEndpoints(endpoints => { // 使用 RouteAttribute endpoints.MapControllers(); });
通过这样子的方式把 OrderController 的路由注入进来
启动程序,可以看到一共有五个接口

第一个接口是我们实现的自定义约束,点击 try it out 后输入参数

第二个接口约束最大为20
输入5,执行

可以看到响应码是 200
输入25,执行

可以看到响应码是 404,也就说路由匹配失败了
第三个接口因为参数是必须的,所以没办法输入空值,有一个前端的验证
第四个接口以三个数字开始,输入 234,符合正则表达式,响应码 200

原文出处:微信公众号【郑子铭 DotNet NB】
原文链接:https://mp.weixin.qq.com/s/E7lAlYWW9k2WIsWbHMMlyg
本文观点不代表Dotnet9立场,转载请联系原作者。