• .NET Core开发实战(第25课:路由与终结点:如何规划好你的Web API)--学习笔记(上)


    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

    知识共享许可协议

    本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。

    欢迎转载、使用、重新发布,但务必保留文章署名 郑子铭 (包含链接: http://www.cnblogs.com/MingsonZheng/ ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。

    如有任何疑问,请与我联系 (MingsonZheng@outlook.com) 。

  • 相关阅读:
    [C#性能简析]泛型集合的使用
    理解自定义特性(Attribute)
    C语言第1次作业2.0版
    C语言第3次作业
    C语言第1次作业
    C语言第2次作业
    kubernetes 部署metricserver
    安装nginx
    C# Winform应用程序内存回收
    asp.net 数据库访问操作类
  • 原文地址:https://www.cnblogs.com/MingsonZheng/p/12508156.html
Copyright © 2020-2023  润新知