使用.NET Core在RESTful API中進行路由操作


介紹

當列出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創建的默認控制器,

使用.NET Core在RESTful API中進行路由操作

  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。

使用.NET Core在RESTful API中進行路由操作

  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框架中啟用默認路由作為屬性路由,關閉了使用路由的所有可能的線程差異。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM