介绍

当列出REST API的最佳实践时,Routing(路由)总是使它位于堆栈的顶部。今天,在这篇文章中,我们将使用特定于.NET Core的REST(web)API来处理路由概念。

对于新手API开发人员,技术顾问以及与REST API相关的所有其他IT专业人员(尤其是使用Microsoft技术堆栈),本文将解释使用Microsoft .NET Core在REST API中重点关注属性路由的重要性和功能。

概论

路由是开发者社区中众多公开争论的话题,这是一个有趣的功能,可以深入研究。路由是API使用的基于功能的标记或Uri模板,以匹配期望执行的所需操作或方法。在开发过程中有两种类型或两种不同类型的路由。也就是说,'Convention-Based Routing'是REST路由家族中的长子,之后是'Attribute Routing',是迄今为止最可爱的儿子。如前所述,在API开发和设计阶段,使用哪种类型的路由机制是一个值得讨论的话题。

在“基于约定的路由”中,路由模板是由开发人员根据需要定义的,基本上是一组带有参数的文本类型的字符串。收到请求后,它会尝试将请求的URI与此定义的路由模板进行匹配。使用这种路由类型的唯一好处是,模板是在应用程序解决方案结构中的单个位置定义的,在控制器和操作中虔诚地利用模板规则。

那么,为什么属性路由很重要?是的,这不仅是重要的,而且强烈建议社区开发人员和架构师开发API。虽然基于约定的路由有其自己的优点,但是在构建一个好的API的时候,很少考虑这种类型的路由是不可取的。REST API中有通用的URI模式,这很难通过基于约定的路由来支持。考虑一组响应数据或资源,往往被分层数据或子资源夹杂着。例如。部门有员工,歌曲有歌手,电影有演员等等。在这种情况下预期的URI是,

/电影/ 1 /演员

在多个控制器和巨大资源的情况下,这种类型的URI虽然可以使用基于约定的路由来实现,但是以缩放和性能为代价是困难的。这是设计可扩展API的关键考虑因素。这里是另一个路由类型,属性路由,扮演一个角色。

属性路由

什么是属性路由?

从技术上说,属性路由就是将路由作为一个属性附加到特定的控制器或操作方法。装饰控制器及其使用[Route]属性定义路由的方法称为属性路由。简单来说,在控制器和方法中使用[Route]属性是Attribute Routing。

[Route(“api / customers / {id} / orders”)]

它从Web API 2开始,现在是RESTful APIs设计和开发中最推荐和改编的路由类型。

为什么使用属性路由?

如名称所示,属性路由使用属性来定义路由。通过属性路由,您可以精确地控制URI,而不是基于约定的路由。以上所述的分层资源场景可以通过属性路由轻松实现,不会对API的可扩展性造成影响。

另外,版本控制API,重载URI段和多参数类型模式可以通过属性路由轻松实现。

使用属性路由

控制器上的任何路由属性都会使控制器中的所有操作属性路由。为动作定义路由属性或控制器优先于传统路由。让我们更精确的.NET Core API,它默认带有属性路由。属性路由需要详细的输入来指定路由。但是,它允许更多地控制哪个路由模板适用于每个操作。

配置

当您使用.NET Core框架创建WEB API时,您可以在其Startup.cs文件中注意到,

  1. void Configure(IApplicationBuilder app,IHostingEnvironment env,ILoggerFactory loggerFactory){

  2. app.UseMvc();

  3. }

在配置部分声明'app.UseMvc()',可以启用属性路由。这是.NET Core应用程序的默认配置。因此,启用.NET Core Web API的属性路由不需要显式配置。

命名空间下面用于装饰[Route]作为属性。

使用Microsoft.AspNetCore.Mvc;

与Web API在MVC路由上的核心区别在于,它使用HTTP方法而不是URI路径来选择操作。属性路由还使用HTTP动作动词来根据请求定义对控制器下方法的操作。

[HttpGet],[HttpPost],HttpPut(“{id}”)],[HttpDelete(“{id}”)]和所有其他记录的动作动词。

在.NET Core项目中,默认情况下,控制器使用指定相应的HTTP动作动词的CRUD方法进行修饰。

下面是由.NET Core创建的默认控制器,

  1. using System;

  2. using System.Collections.Generic;

  3. using System.Linq;

  4. using System.Threading.Tasks;

  5. using Microsoft.AspNetCore.Mvc;

  6. namespace WebAPIwiithCore.Controllers

  7. {

  8. [Route(“API / [Controller]” )]

  9. publicclassMoviesController:Controller

  10. {

  11. //获取api /值

  12. [HTTPGET]

  13. publicIEnumerable <string> Get()

  14. {

  15. returnnewstring [] { “value1” , “value2” };

  16. }

  17. //获取api / values / 5

  18. [HttpGet(“{id}” )]

  19. public String get(int id)

  20. {

  21. 返回“价值” ;

  22. }

  23. // POST api / values

  24. [HttpPost]

  25. publicvoid Post([FromBody] string Value)

  26. {

  27. }

  28. // PUT api / values / 5

  29. [HttpPut(“{id}” )]

  30. publicvoid Put(int id,[FromBody] string value)

  31. {

  32. }

  33. //删除api / values / 5

  34. [HttpDelete(“{id}” )]

  35. publicvoid删除(int id)

  36. {

  37. }

  38. }

  39. }

如果您注意到,控制器类“ValuesController”是由路由装饰的,

〔Route( “API / [Controller]”)]

该功能是在称为路由令牌的.NET核心框架中引入的。令牌[controller]从定义路由的动作或类中替换控制器名称的值。

这里的控制器名称是由路由控制器令牌装饰的值,

  1. [Route(“API / [Controller]” )]

  2. publicclassValuesController:Controller {...} //匹配'/ api / Values'

现在让我们将控制器名称更改为MoviesController;

  1. [Route(“API / [Controller]” )]

  2. publicclassMoviesController:Controller {...} //现在匹配'/ api / Movies'

在这里,URI'api / values'正在工作得更好,现在它会抛出一个错误(404找不到)。使用“api / Movies”更改URI将提供所需的响应。

对于[行动]和[区域],各自的行动方式和领域也是如此。

现在,让我们考虑下面的例子,

  1. [Route(“API / [Controller” )]

  2. publicclassMoviesController:Controller {

  3. [HTTPGET]

  4. publicIEnumerable <string> Get(){

  5. returnnewstring [] {

  6. “value1” ,

  7. “value2”

  8. };

  9. }

  10. [HttpPost]

  11. publicvoid Post([FromBody] string value){

  12. return;

  13. }

  14. }

对于上面给出的代码片段,

URI,

  1. // Get / api / Movies /将匹配方法1。

  1. // Post / api / Movies /将匹配方法2。

请注意,这两个URI是相同的,唯一的区别在于它是如何被Get或Post方法调用的。这使Web API路由不同于MVC路由。

模式

让我们看一下其他几个例子,如上所述,通过属性路由来缓解。

API版本控制

在本例中,“Get / api / movies / v1 /”将被路由到方法1,“Get / api / movies / v2 /”将被路由到方法2。

  1. [Route(“API / [Controller]” )]

  2. publicclassMoviesController:Controller {

  3. [HttpGet(“v1” )]

  4. publicIEnumerable <string> Get(){

  5. returnnewstring [] {

  6. “V1.value1” ,

  7. “V1.value2”

  8. };

  9. }

  10. [HttpGet(“v2” )]

  11. publicIEnumerable <string> Get(){

  12. returnnewstring [] {

  13. “V2.value1” ,

  14. “V2.value2”

  15. };

  16. }

  17. }

请注意,版本控制主要由不同的控制器处理。这里为了便于理解,我们倾向于用不同的方法用相同的签名来描述它。

示例清楚地表明,属性路由是如何处理复杂情况的最简单方法。

重载的URI

在这个例子中,“id”是一个可以作为数字传递的参数,但是“knownited”映射到一个集合。

  1. [Route(“API / [Controller]” )]

  2. publicclassMoviesController:Controller {

  3. [HttpGet(“{id}” )]

  4. publicIEnumerable <string> Get(int id){

  5. returnnewstring [] {

  6. “V2.value1” ,

  7. “V2.value2”

  8. };

  9. }

  10. [HttpGet(“get” )]

  11. publicIEnumerable <string> Get(){

  12. returnCollections ..

  13. }

  14. }

URI,

  1. // Get / api / Movies / 123将匹配方法1。

  1. // Get / api / Movies / notedited将匹配方法2。

多个参数类型

在这个例子中,“id”是一个参数,可以作为数字或字母表传递任何空闲的字符串。

  1. [Route(“API / [Controller]” )]

  2. publicclassMoviesController:Controller {

  3. [HttpGet(“{id:int}” )]

  4. publicIEnumerable <string> Get(int id){

  5. returnnewstring [] {

  6. “V2.value1” ,

  7. “V2.value2”

  8. };

  9. }

  10. [HttpGet(“id:aplha” )]

  11. publicIEnumerable <string> Get(string id){

  12. returnnewstring [] {

  13. “V2.value1” ,

  14. “V2.value2”

  15. };

  16. }

  17. }

URI,

  1. // Get / api / Movies / 123将匹配方法1。

  1. // Get / api / Movies / abc将匹配方法2。

上面的例子有一些需要注意的地方,

HTTPGET( “{ID:int”)]

提到参数数据类型被接受,被称为约束。我们将在后面的文章中通过这个。

多个参数

在这个例子中,'id'和'authorid'是一个可以作为数字传递的参数。

  1. [Route(“API / [Controller]” )]

  2. publicclassBooksController:Controller {

  3. [HttpGet(“{id:int} / author / {authorid:int}” )]

  4. publicIEnumerable <string> Getdetails(int id,intauthorid){

  5. returnnewstring [] {

  6. “V2.value1” ,

  7. “V2.value2”

  8. };

  9. }

  10. }

匹配URI:// Get api / books / 1 / author / 5在给定的方法中,where 1与'id'和'5'匹配authorid。

多个路线

属性路由允许我们为相同的控制器和动作或方法定义多个路由。让我们用例子来理解它,

  1. [Route(“API / [Controller]” )]

  2. publicclassMoviesController:Controller {

  3. [HttpPut(“Post” )]

  4. [HttpPost(“Checkout” )]

  5. publicMovieordermovie(){

  6. return SomeValue...

  7. }

  8. }

如示例中所示,Method'Ordermovie'返回模型类“Movie”的某个值。该方法定义了两个路由。一个带有HTTP动词Put,主要用于CRUD中的更新操作,另一个带有HTTP动词Post,用于创建或添加数据。两者都指的是相同的方法。

在这种情况下,下面的URI将匹配路由,

URI 1匹配// PUT api / movies /购买

URI 2匹配//发布api /电影/结帐

备注

路线1和路线2用于更好的理解目的,与订购无关。

我们甚至可以在控制器上定义多个路由。在这种情况下,来自控制器的两条路线都与两条路线相结合。看下面的例子,

  1. [Route(“api / Store” )]

  2. [Route(“API / [Controller]” )]

  3. publicclassMoviesController:Controller {

  4. [HttpPut(“post )]

  5. [HttpPost(“Checkout” )]

  6. publicMovieordermovie(){

  7. returnSomeValue..

  8. }

  9. }

在这种情况下,下面的URI将匹配路由,

URI 1匹配// PUT api / movies / buy&api / store / buy

URI 2匹配//发布api /电影/结帐&api / store / checkout

路线约束

路由约束提供对路由中使用的匹配参数的控制。在路由中定义参数的语法是“{parameter:constraint}”。

  1. [HttpGet(“api / constraint / {id:int}” )]

  2. publicIEnumerable <string> Get(int id){

  3. returnnewstring [] {

  4. “V2.value1” ,

  5. “V2.value2”

  6. };

  7. }

匹配路由:api / constraint / 1

只有整数值将被路由到“有效”资源的“Get”方法。任何其他非整数值都不会受到方法的影响,比如api / constraint / abc将不会被路由。

在这里,可能有一个问题。如果客户端调用,api / constraint / 0仍然会被路由到Get方法,这是错误的。所以为了遏制这个问题,我们可以为参数接受大于零的值添加另一个约束。这可以通过添加约束'min(1)'来实现,其中1是由“min”约束接受的参数。()“括号中可以接受参数

我们可以通过用冒号分隔约束来在单个参数上添加多个约束。

语法

“{参数:约束:约束}”。

  1. [HttpGet(“api / constraint / {id:int:min(1)}” )]

  2. publicIEnumerable <string> Get(int id){

  3. returnnewstring [] {

  4. “V2.value1” ,

  5. “V2.value2”

  6. };

  7. }

的URI

  1. api / constraint / 1||> 1将匹配。

  2. api / constraint / 0不匹配。

  3. api / constraint / -1或负数不匹配。

类似的约束,比如字符串的'alpha',布尔值的'bool',日期时间的'datetime'值,'min','max','range'和特定范围的值等。

属性路由功能虽然是API设计栈中最推荐的实现。从API的可扩展性到API让客户端可读,属性路由在API开发中扮演着重要的角色。Microsoft在其.NET Core框架中启用默认路由作为属性路由,关闭了使用路由的所有可能的线程差异。

使用.NET Core在RESTful API中进行路由操作的更多相关文章

  1. 使用ASP.NET Core构建RESTful API的技术指南

    译者荐语:利用周末的时间,本人拜读了长沙.NET技术社区翻译的技术标准<微软RESTFul API指南>,打算按照步骤写一个完整的教程,后来无意中看到了这篇文章,与我要写的主题有不少相似之 ...

  2. Restful API 中的错误处理

    简介 随着移动开发和前端开发的崛起,越来越多的 Web 后端应用都倾向于实现 Restful API. Restful API 是一个简单易用的前后端分离方案,它只需要对客户端请求进行处理,然后返回结 ...

  3. 【ASP.NET Web API教程】4.1 ASP.NET Web API中的路由

    原文:[ASP.NET Web API教程]4.1 ASP.NET Web API中的路由 注:本文是[ASP.NET Web API系列教程]的一部分,如果您是第一次看本博客文章,请先看前面的内容. ...

  4. Web API中的路由(一)——约定路由

    一.Web API中的路由概念 路由的作用用一句话说明:通过request的uri找到处理该请求的Controller,Action,以及给Action的参数赋值. 一些路由的基本概念: route: ...

  5. ASP.NET WEB API 中的路由调试与执行过程跟踪

    路由调试 RouteDebugger 是调试 ASP.NET MVC 路由的一个好的工具,在ASP.NET WEB API中相应的有 WebApiRouteDebugger ,Nuget安装 Inst ...

  6. Web API中的路由(二)——属性路由

    一.属性路由的概念 路由让webapi将一个uri匹配到对应的action,Web API 2支持一种新类型的路由:属性路由.顾名思义,属性路由使用属性来定义路由.通过属性路由,我们可以更好地控制We ...

  7. ASP.NET Web API中的路由

    ASP.NET Web API的默认路由在App_Start目录中的WebApiConfig.cs文件中定义的. public static class WebApiConfig { public s ...

  8. Java 8 Stream Api 中的 peek 操作

    1. 前言 我在Java8 Stream API 详细使用指南[1] 中讲述了 [Java 8 Stream API]( "Java 8 Stream API") 中 map 操作 ...

  9. [json-server] RESTful API 中,取主数据时,同时获取多个关联子表的数据

    项目背景: back-end:ASP.NET Core WebAPI front-end:Vue(+vue-router +vuex +axios)(webpack)(json-server + mo ...

随机推荐

  1. 史上前端面试最全知识点(附答案)---html & js & css

    史上前端面试最全知识点(附答案) 一.html & js & css 1.AMD和CMD是什么?它们的区别有哪些? AMD和CMD是二种模块定义规范.现在都使用模块化编程,AMD,异步 ...

  2. Simple Validation in WPF

    A very simple example of displaying validation error next to controls in WPF Introduction This is a ...

  3. 容器平台选型的十大模式:Docker、DC/OS、K8S 谁与当先?

    作者:刘超   来自:网易云 基础服务 无论是在社区,还是在同客户交流的过程中,总会被问到到底什么时候该用 Docker?什么时候用虚拟机?如果使用容器,应该使用哪个容器平台? 显而易见,我不会直接给 ...

  4. 测试String.Format中的Format参数

    DateTime datetime = DateTime.Now; Console.WriteLine(String.Format("{0:d}", datetime)); // ...

  5. win10 + python3.6 + VSCode + tensorflow-gpu + keras + cuda8 + cuDN6N环境配置

    写在前面的话: 再弄这个之前,我对python也好,tensorflow也好几乎是0认知的,所以配置这个环境的时候,走了不少弯路,整整耗费了一个星期的时间才搭配完整这个环境,简直了...然而最气的是, ...

  6. KDevelop使用笔记【中文】

    师从官方文档: https://userbase.kde.org/KDevelop4/Manual https://docs.kde.org/trunk5/en/extragear-kdevelop/ ...

  7. UWP 手绘视频创作工具技术分享系列 - 手绘视频导出

    手绘视频最终的生成物是视频文件,前面几篇主要讲的是手绘视频的创作部分,今天讲一下手绘视频的导出问题.主要以 UWP 为例,另外会介绍一些 Web 端遇到的问题和解决方法. 如上所述,手绘视频在创作后, ...

  8. 关于Python输出时间戳的问题

    在我们的程序中,有时候想要知道程序的执行时间或者准确的停止时间,这时候就需要我们自己添加一个时间戳,以便我们做出判断和相应的处理. 下面是我亲测并收集的资料,菜鸟一枚,不全之处大神可给予补充和指正. ...

  9. 【hihoCoder】#1039 : 字符消除 by C solution

    #1039 : 字符消除 时间限制:1000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi最近在玩一个字符消除游戏.给定一个只包含大写字母"ABC"的字符串s,消 ...

  10. PHP使用header方式实现文件下载

    php文件下载可以使用http的请求头加上php的IO可以实现,很久之前写过这么一个功能,后来代码没了,今天记录一下 1.先看一下一个正常的http请求 HTTP/1.1 200 OK Server: ...