本文將延續本站《使用Visual Studio Code設計ASP.NET Core Web API - 1》一文的情境,介紹如何在ASP.NET Core Web API專案中設計資料模型、資料服務,以及控制器的程式碼,以處理各種不同的HTTP請求,例如使用 CRUD 操作(新增、讀取、更新、刪除)處理資料。
設計資料模型
在設計 Web API 之前,我們需要提供執行作業的資料暫存區,通常會使用模型類別來代表,我們將加入一個「Book」類別代表圖書資料。 模型中定義代表圖書特性的屬性。 模型將應用在 Web API 中傳遞資料,以及用來將圖書資料保存在資料存放區中,在這個文章中我們會將資料放在本機記憶體內部快取之中。
接下來來設計設計「Book」模型。先在終端機視窗執行下列命令,建立「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」資料夾:
在 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;
}
}
}
}
|
在終端機視窗命令提示字元執行下列命令,以建置應用程式:
這個命令的執行結果請參考下圖所示:
圖 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 | [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 | [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程式:
這個命令的執行結果請參考下圖所示:
圖 3:執行Web API程式。
使用 .HTTP 檔案測試控制器
開啟 「MyWebAPI.http」檔案,在分隔符「###」下方加入以下兩個「GET」程式碼:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | @MyWebAPI_HostAddress = http:
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:
###
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 請求:
這個命令的執行結果請參考下圖所示:
圖 7:使用.NET HTTP REPL命令測試控制器。
執行下列命令,查看端點:
執行下列命令,以前往「Book」端點:
使用下列命令,透過「HttpRepl」送出「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 | [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 | [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 | [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:
然後使用「.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:
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:
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:
###
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」開啟一個新的整合式終端機,在其中輸入並執行命令:
執行下列命令,查看端點:
這些命令的執行結果請參考下圖所示:
圖 12:httprepl連線到服務。
執行下列命令,以前往「Book」端點:
使用下列命令,透過「HttpRepl」送出 POST請求,利用「-f」參數指定資料所在的檔案:
這些命令的執行結果請參考下圖所示:
圖 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」開啟一個新的整合式終端機,在其中輸入並執行命令:
執行下列命令,查看端點:
這個命令的執行結果請參考下圖所示:
圖 14:httprepl連線到服務。
執行下列命令,以前往「Book」端點:
執行下列命令,查看端點:
s
這時你應該可以看到一個{id}端點,請參考下圖所示:
圖 15:{id}端點。
使用下列命令,透過「HttpRepl」中送出「PUT」請求:
使用「get」命令取回修改結果,比對資料是否正確被修改:
這些命令的執行結果請參考下圖所示:
圖 16:修改資料。
重複之前的動作,在終端機視窗輸入並執行命令,刪除編號為「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請求的方法。