使用Visual Studio Code設計ASP.NET Core Web API - 2
作者:許薰尹 精誠資訊/恆逸教育訓練中心資深講師
本文將延續本站《使用Visual Studio Code設計ASP.NET Core Web API - 1》一文的情境,介紹如何在ASP.NET Core Web API專案中設計資料模型、資料服務,以及控制器的程式碼,以處理各種不同的HTTP請求,例如使用 CRUD 操作(新增、讀取、更新、刪除)處理資料。
設計資料模型
在設計 Web API 之前,我們需要提供執行作業的資料暫存區,通常會使用模型類別來代表,我們將加入一個「Book」類別代表圖書資料。 模型中定義代表圖書特性的屬性。 模型將應用在 Web API 中傳遞資料,以及用來將圖書資料保存在資料存放區中,在這個文章中我們會將資料放在本機記憶體內部快取之中。
接下來來設計設計「Book」模型。先在終端機視窗執行下列命令,建立「Models」資料夾:
1 | mkdir Models |
在 Visual Studio Code 開發工具中選取「Models」資料夾,並按下「New File」按鈕,新增一個名為「Book.cs」的新檔案。
圖 1:新增「Book.cs」檔案。
新增下列程式碼到「Book.cs」之中:
1 2 3 4 5 6 7 8 9 10 11 12 | namespace MyWebAPI.Models { public class Book { public int Id { get ; set ; } public string Title { get ; set ; } public decimal Price { get ; set ; } public DateTime PublishDate { get ; set ; } public bool InStock { get ; set ; } public string Description { get ; set ; } } } |
設計資料服務
在終端機視窗執行下列命令來建立「Services」資料夾:
1 | mkdir Services |
在 Visual Studio Code 開發工具中選取「Services」資料夾,並新增一個名為「BookService.cs」的新檔案。然後加入下列程式碼,建立圖書資料服務:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | using System; using System.Collections.Generic; using MyWebAPI.Models; namespace MyWebAPI.Services { public static class BookService { public static List<Book> Books { get ; private set ; } static BookService() { Books = new List<Book>() { new Book() { Id = 1 , Title = " Essential Programming Language " , Price = 250 , PublishDate = new DateTime( 2019 ,1,2 ) , InStock = true , Description = "Essential Programming Language " , }, new Book() { Id = 2 , Title = " Telling Arts " , Price = 245 , PublishDate = new DateTime( 2019 , 4 , 15 ) , InStock = true , Description = " Telling Arts " , }, new Book() { Id = 3 , Title = " Marvel " , Price = 150 , PublishDate = new DateTime( 2019 , 2, 21 ) , InStock = true , Description = " Marvel " , }, new Book() { Id = 4 , Title = " The Beauty of Cook" , Price = 450 , PublishDate = new DateTime( 2019 ,12,2 ) , InStock = true , Description = " The Beauty of Cook " , } }; } public static List<Book> GetAllBooks() { return Books; } public static Book? GetBookById( int id ) { return Books.Find( book => book.Id == id ); } public static void AddBook( Book book ) { int newId = Books.Count + 1; book.Id = newId; Books.Add( book ); } public static void DeleteBookById( int id ) { Book bookToRemove = Books.Find( book => book.Id == id ); if ( bookToRemove != null ) { Books.Remove( bookToRemove ); } } public static void UpdateBook( int id, Book book ) { Book bookToUpdate = Books.Find( book => book.Id == id ); if ( bookToUpdate != null ) { bookToUpdate.Title = book.Title; bookToUpdate.Price = book.Price; bookToUpdate.PublishDate = book.PublishDate; bookToUpdate.InStock = book.InStock; bookToUpdate.Description = book.Description; } } } } |
在終端機視窗命令提示字元執行下列命令,以建置應用程式:
1 | dotnet build |
這個命令的執行結果請參考下圖所示:
圖 2:建置應用程式。
設計控制器
在ASP.NET Core Web API中,控制器是一個用來處理來自用戶端的HTTP請求的類別。每個控制器可以包含一個或多個動作(方法),這些動作負責處理各種不同的HTTP請求,例如GET、POST、PUT等。
在 Visual Studio Code 開發工具中選取「Controllers」資料夾,並新增一個名為「BookController.cs」的新檔案,依照慣例,控制器類別名稱的字尾會加上 「Controller」字串。在「BookController.cs」檔案中加入以下程式碼:
1 2 3 4 5 6 7 8 9 10 11 12 | using System; using Microsoft.AspNetCore.Mvc; namespace MyWebAPI.Controllers { [ApiController] [Route( "[controller]" )] public class BookController : ControllerBase { } } |
控制器是一個公開類別,通常繼承自「ControllerBase」類別,類別上方套用[ApiController] 和 [Route]。
取得所有圖書資料
控制器類別包含處理不同HTTP請求的方法,這些方法稱為「動作」,它們是公開方法,用來對應特定的HTTP請求。
我們要撰寫的第一個REST指令動詞為「GET」,讓用戶端能夠從API獲取所有圖書的資訊。我們可以利用內建的[HttpGet]屬性,來定義一個方法,負責從服務取回圖書清單,在「BookController」類別加入以下程式碼:
1 2 3 4 5 6 | //Get All Books [HttpGet] public IActionResult GetAll() { return Ok( MyWebAPI.Services.BookService.GetAllBooks() ); } |
上述程式具有以下特點:
- 僅回應標識[HttpGet]屬性的HTTP GET請求。
- 回傳一個List 類型的IActionResult實例。
- 「GetAll」動作會叫用服務來查詢所有圖書,並自動設定「Content-Type」為「application/json」來回傳資料。
讀取單一圖書資料
用戶端可能會需要查詢特定圖書的詳細資料,而不是整個圖書清單。為此,我們可以設計一個帶有「id」參數的「GET」動作。使用內建的[HttpGet("{id}")]屬性定義一個方法,從服務中取回特定的圖書資料。在「BookController」類別加入以下程式碼:
1 2 3 4 5 6 7 | //Get Book by Id [HttpGet( "{id}" )] public ActionResult<Book> Get( int id ) { var book = MyWebAPI.Services.BookService.GetBookById( id ); return book != null ? Ok( book ) : NotFound( ); } |
Web API的路由系統會根據是否提供id,來決定叫用[HttpGet](無id)和[HttpGet("{id}")](帶有id)兩個方法。
建置並測試控制器資料查詢
在終端機視窗命令提示字元執行下列命令以執行Web API程式:
1 | dotnet run |
這個命令的執行結果請參考下圖所示:
圖 3:執行Web API程式。
使用 .HTTP 檔案測試控制器
開啟 「MyWebAPI.http」檔案,在分隔符「###」下方加入以下兩個「GET」程式碼:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | @MyWebAPI_HostAddress = http: //localhost:5052 GET {{MyWebAPI_HostAddress}}/weatherforecast/ Accept: application/json ### GET {{MyWebAPI_HostAddress}}/Book/ Accept: application/json ### GET {{MyWebAPI_HostAddress}}/Book/1 Accept: application/json ### |
選取「GET」上方的 「Send Request」命令傳送要求,此命令將會以 JSON 格式傳回所有圖書的清單,這個命令的執行結果請參考下圖所示:
圖 4:送出GET請求取回所有圖書資料。
按相同的方式測試最後一個「GET」請求,取回一本圖書資料,這個命令的執行結果請參考下圖所示:
圖 5:送出「GET」請求取「id」相符的圖書資料。
我們的 API 也會處理資料不存在的情況。 若再次呼叫 API,故意使用下列命令傳入無效的圖書id編號:
1 2 3 4 5 6 | @MyWebAPI_HostAddress = http: //localhost:5052 ### GET {{MyWebAPI_HostAddress}}/Book/100 Accept: application/json ### |
這時將會傳回 「404 Not Found」錯誤,請參考下圖所示:
圖 6:「404 Not Found」 錯誤。
使用HTTP REPL 命令測試控制器
在 Visual Studio Code 開發工具中選擇「 Terminal 」> 「New Terminal」開啟一個新的整合式終端機,在其中輸入並執行命令,以 .NET HTTP REPL 命令列工具,來送出HTTP 請求:
1 | connect http: //localhost:5052 |
這個命令的執行結果請參考下圖所示:
圖 7:使用.NET HTTP REPL命令測試控制器。
執行下列命令,查看端點:
1 |
執行下列命令,以前往「Book」端點:
1 | cd Book |
使用下列命令,透過「HttpRepl」送出「GET」請求:
1 | Get |
這些命令的執行結果請參考下圖所示:
圖 8:使用HTTP REPL 命令測試控制器。
ASP.NET Core中的CRUD動作
我們的圖書服務提供支援圖書清單的 CRUD(建立、讀取、更新、刪除)操作。這些操作是透過不同的HTTP指令動詞來實現的,並且在ASP.NET Core中,這些動詞由特定的屬性來對應。例如從服務取得一個或多個項目的HTTP GET指令動詞,會透過使用[HttpGet]屬性來標示相應的動作方法。同樣的道理,[HttpPost]可用來標示資料新增的動作方法;[HttpPut] 可用來標示資料修改的動作方法;[HttpDelete] 可用來標示資料刪除的動作方法;
「POST」動作
我們已經看過「GET」動作的運作方式, 現在就來深入了解「POST」、「PUT」和 「DELETE」動作。我們先使用「POST」方法,透過 Web API 新增圖書資料,在「BookController」類別加入以下程式碼:
1 2 3 4 5 6 7 | // Add Book [HttpPost] public IActionResult AddBook( Book book ) { MyWebAPI.Services.BookService.AddBook( book ); return Created( $ "/book/{book.Id}" , book ); } |
「AddBook」方法上標註 [HttpPost],用來處理發送到 Book API 的 HTTP「POST」請求。和「Get」方法回傳圖書清單不同的是,這方法會回傳「IActionResult」。「IActionResult」使用戶端能夠了解請求是否執行成功,若成功便提供新建立的圖書「ID」。利用標準的 HTTP 狀態碼,「IActionResult」確保無論用戶端使用的程式語言或開發平台是什麼,都能夠輕鬆地實現與用戶端的整合。
「PUT」動作
修改或更新我們圖書的程式類似於之前實作的「POST」方法,但需要搭配使用[HttpPut]屬性。除此之外,除了需要更新的「Book」物件之外,還需要一個「id」參數。接著,使用「PUT」方法,透過 Web API 更新圖書。在「BookController」類別加入以下程式碼:
1 2 3 4 5 6 7 8 9 10 11 12 13 | // Update Book [HttpPut( "{id}" )] public IActionResult UpdateBook( int id, Book book ) { var existingBook = MyWebAPI.Services.BookService.GetBookById( id ); if (existingBook == null ) { return NotFound(); } book.Id = id; MyWebAPI.Services.BookService.UpdateBook( id, book ); return NoContent(); } |
「DELETE」動作
Web API其中一個較簡單要實作的動作是「DELETE」動作,只接受圖書的「id」參數,以便從記憶體內部快取中移除。在「BookController」類別加入以下程式碼:
1 2 3 4 5 6 7 8 9 10 11 12 | // Delete Book [HttpDelete( "{id}" )] public IActionResult DeleteBook( int id ) { var existingBook = MyWebAPI.Services.BookService.GetBookById( id ); if ( existingBook == null ) { return NotFound(); } MyWebAPI.Services.BookService.DeleteBookById( id ); return NoContent(); } |
建置並執行完成的 Web API
我們已經完成Web API的設計了,現在讓我們來測試看看。在終端機視窗命令提示字元執行下列命令,建立並啟動 Web API:
1 | dotnet run |
然後使用「.HTTP」檔案測試已完成的 Web API,重新開啟「MyWebAPI.http」 檔案,使用下列命令來送出「POST」要求,以新增圖書:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | @MyWebAPI_HostAddress = http: //localhost:5052 POST {{MyWebAPI_HostAddress}}/Book/ Content-Type: application/json Accept: application/json { "id" : 100, "title" : "Book 100" , "price" : 100, "PublishDate" : "2021-01-01T00:00:00" , "InStock" : true , "Description" : "Book 100 Description" } ### |
上述命令會傳回新建立的圖書,執行結果請參考下圖所示:
圖 9:新增圖書。
在終端機視窗命令提示字元執行下列命令,以 「PUT」要求來更新圖書:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | @MyWebAPI_HostAddress = http: //localhost:5052 PUT {{MyWebAPI_HostAddress}}/Book/1 Content-Type: application/json Accept: application/json { "id" : 1, "title" : "New Book 1" , "price" : 100, "PublishDate" : "2021-01-01T00:00:00" , "InStock" : false , "Description" : "New Book 1 Description" } ### |
上述命令會傳回下列訊息,表示成功:
1 2 3 4 | HTTP/1.1 204 No Content Connection: close Date: Thu, 29 Feb 2024 05:51:06 GMT Server: Kestrel |
這個命令的執行結果請參考下圖所示:
圖 10:修改資料。
在終端機視窗命令提示字元執行下列命令,以透過「DELETE」動作來刪除圖書:
1 2 3 4 5 | @MyWebAPI_HostAddress = http: //localhost:5052 ### DELETE {{MyWebAPI_HostAddress}}/Book/1 |
上述命令會傳回下列訊息,表示成功,請參考下圖所示:
圖 11:刪除圖書。
使用HTTP REPL命令測試已完成的 Web API
先在專案根目錄加入一個「data.json」檔案,包含要新增的資料,使用JSON格式:
1 | { "id" : 100, "title" : "Book 100" , "price" : 100, "PublishDate" : "2021-01-01T00:00:00" , "InStock" : true , "Description" : "Book 100 Description" } |
在 Visual Studio Code 開發工具 中選擇 >「 Terminal 」> 「New Terminal」開啟一個新的整合式終端機,在其中輸入並執行命令:
1 | httprepl http: //localhost:5052 |
執行下列命令,查看端點:
1 |
這些命令的執行結果請參考下圖所示:
圖 12:httprepl連線到服務。
執行下列命令,以前往「Book」端點:
1 | cd Book |
使用下列命令,透過「HttpRepl」送出 POST請求,利用「-f」參數指定資料所在的檔案:
1 | POST -f data.json |
這些命令的執行結果請參考下圖所示:
圖 13:新增資料。
接著我們修改「data.json」檔案,修改編號「1」的圖書「title」等資料:
1 | { "id" : 1, "title" : "Book 101" , "price" : 100, "PublishDate" : "2021-01-01T00:00:00" , "InStock" : true , "Description" : "Book 101 Description" } |
重複之前的動作,在 Visual Studio Code 開發工具 中選擇 >「 Terminal 」> 「New Terminal」開啟一個新的整合式終端機,在其中輸入並執行命令:
1 | httprepl http: //localhost:5052 |
執行下列命令,查看端點:
1 |
這個命令的執行結果請參考下圖所示:
圖 14:httprepl連線到服務。
執行下列命令,以前往「Book」端點:
1 | cd Book |
執行下列命令,查看端點:
1 |
這時你應該可以看到一個{id}端點,請參考下圖所示:
圖 15:{id}端點。
使用下列命令,透過「HttpRepl」中送出「PUT」請求:
1 | Put -f data.json |
使用「get」命令取回修改結果,比對資料是否正確被修改:
1 | get |
這些命令的執行結果請參考下圖所示:
圖 16:修改資料。
重複之前的動作,在終端機視窗輸入並執行命令,刪除編號為「1」的資料:
1 | delete 1 |
使用「get」命令取回圖書資料,比對資料是否正確被修改:
1 | get |
這些命令的執行結果請參考下圖所示:
圖 17:刪除資料。
總結
在這一系列文章,我們介紹了如何在 .NET 平台上建立一個運行ASP.NET Core Web API的應用程式。這個Web API利用快取來建立、讀取、修改和刪除圖書資料。現在你已掌握了以下使用ASP.NET Core建立Web API的關鍵步驟:
- 利用ASP.NET Core Web API範本建立一個Web API應用程式。
- 建立一個繼承自ControllerBase類別的類別,該類別包含用於響應HTTP請求的方法。
- 使用工具來測試Web API的運作。
0 意見:
張貼留言