注意
這不是這篇文章的最新版本。 如需目前的版本,請參閱 本文的 .NET 9 版本。
警告
不再支援此版本的 ASP.NET Core。 如需詳細資訊,請參閱 .NET 和 .NET Core 支持原則。 如需目前的版本,請參閱 本文的 .NET 9 版本。
由 普拉提克·汗德爾瓦爾 和 斯科特·阿迪
本教學課程會建立 Web API,以在 MongoDB NoSQL 資料庫上執行建立、讀取、更新和刪除 (CRUD) 作業。
在本教學課程中,您會了解如何:
- 設定 MongoDB
- 建立 MongoDB 資料庫
- 定義 MongoDB 集合與結構描述
- 從 Web API 執行 MongoDB CRUD 作業
- 自訂 JSON 序列化
必要條件
具有 ASP.NET 和 Web 開發工作負載的 Visual Studio 2022。
設定 MongoDB
從開發機器上的任何位置啟用 MongoDB 和 Mongo DB 殼層存取 (Windows/Linux/macOS):
下載並安裝 MongoDB Shell:
- macOS/Linux: 選擇要擷取 MongoDB Shell 的目錄。 將針對
mongosh
產生的路徑新增至PATH
環境變數。 - Windows:MongoDB Shell (mongosh.exe) 安裝在 C:\Users\<user>\AppData\Local\Programs\mongosh。 將針對
mongosh.exe
產生的路徑新增至PATH
環境變數。
- macOS/Linux: 選擇要擷取 MongoDB Shell 的目錄。 將針對
下載並安裝 MongoDB:
- macOS/Linux:確認已安裝 MongoDB 的目錄,通常是在 /usr/local/mongodb 中。 將針對
mongodb
產生的路徑新增至PATH
環境變數。 - Windows:MongoDB 預設會安裝在 C:\Program Files\MongoDB 。 將 C:\Program Files\MongoDB\Server\<version_number>\bin 新增至
PATH
環境變數。
- macOS/Linux:確認已安裝 MongoDB 的目錄,通常是在 /usr/local/mongodb 中。 將針對
選擇資料記憶體目錄: 選取開發電腦上的目錄來儲存資料。 若該目錄不存在,請建立它。 MongoDB 殼層不會建立新目錄:
- macOS/Linux: 例如
/usr/local/var/mongodb
。 - Windows: 例如
C:\\BooksData
。
- macOS/Linux: 例如
在 OS 命令殼層 (非 MongoDB 殼層) 中,使用下列命令在預設連接埠 27017 上連線到 MongoDB。 將
<data_directory_path>
取代為上一個步驟中所選擇的目錄。mongod --dbpath <data_directory_path>
在下列步驟中使用先前安裝的 MongoDB 殼層來建立資料庫、建立集合及儲存文件。 如需 MongoDB 殼層命令的詳細資訊,請參閱 mongosh
。
啟動
mongosh.exe
,或在命令殼層中執行下列命令,以開啟 MongoDB 命令殼層實例:mongosh
在命令殼層中,執行下列命令介面以連線到預設測試資料庫:
use BookStore
如果 BookStore 不存在,就會建立名為 BookStore 的資料庫。 若該資料庫存在,會開啟其連線進行交易。
使用下列命令建立
Books
集合:db.createCollection('Books')
顯示的結果如下:
{ "ok" : 1 }
使用下列命令為
Books
集合定義結構描述並插入兩份文件:db.Books.insertMany([{ "Name": "Design Patterns", "Price": 54.93, "Category": "Computers", "Author": "Ralph Johnson" }, { "Name": "Clean Code", "Price": 43.15, "Category": "Computers","Author": "Robert C. Martin" }])
會顯示類似下列的結果:
{ "acknowledged" : true, "insertedIds" : [ ObjectId("61a6058e6c43f32854e51f51"), ObjectId("61a6058e6c43f32854e51f52") ] }
注意
上述結果中顯示的
ObjectId
,不符合命令列介面中顯示的結果。使用下列命令檢視資料庫中的文件:
db.Books.find().pretty()
會顯示類似下列的結果:
{ "_id" : ObjectId("61a6058e6c43f32854e51f51"), "Name" : "Design Patterns", "Price" : 54.93, "Category" : "Computers", "Author" : "Ralph Johnson" } { "_id" : ObjectId("61a6058e6c43f32854e51f52"), "Name" : "Clean Code", "Price" : 43.15, "Category" : "Computers", "Author" : "Robert C. Martin" }
結構描述會為每份文件新增自動生成的
_id
屬性 (類型ObjectId
)。
建立 ASP.NET Core Web API 專案
- 移至 [ 檔案>新>專案]。
- 選取 [ASP.NET Core Web API] 專案型別,然後選取 [下一步]。
- 將專案命名為 BookStoreApi,然後選取 [ 下一步]。
- 在 [其他資訊] 對話方塊中:
- 確認架構為.NET 9.0(標準支援期)。
- 請確認 [使用控制器] 的核取方塊已被勾選。
- 確認已核取 [啟用 OpenAPI 支援 ] 複選框。
- 選擇建立。
在 [套件管理員主控台] 視窗中,瀏覽到專案根目錄。 執行下列命令以安裝適用於 MongoDB 的 .NET 驅動程式:
Install-Package MongoDB.Driver
新增實體模型
將 Models 目錄新增至專案根目錄。
使用下列程式代碼將類別
Book
新增至 Models 目錄:using MongoDB.Bson; using MongoDB.Bson.Serialization.Attributes; namespace BookStoreApi.Models; public class Book { [BsonId] [BsonRepresentation(BsonType.ObjectId)] public string? Id { get; set; } [BsonElement("Name")] public string BookName { get; set; } = null!; public decimal Price { get; set; } public string Category { get; set; } = null!; public string Author { get; set; } = null!; }
在上述類別中,
Id
屬性為:- 將 Common Language Runtime (CLR) 物件對應到 MongoDB 集合所需。
- 使用
[BsonId]
標註,以讓此屬性成為文件的主索引鍵。 - 加上
[BsonRepresentation(BsonType.ObjectId)]
批註,以允許將參數傳遞為型別string
,而非ObjectId結構。 Mongo 會處理從string
轉換到ObjectId
的作業。
BookName
屬性會使用[BsonElement]
屬性標註。Name
的屬性值代表 MongoDB 集合中的屬性名稱。
新增組態模型
將下列資料庫設定值新增至
appsettings.json
:{ "BookStoreDatabase": { "ConnectionString": "mongodb://localhost:27017", "DatabaseName": "BookStore", "BooksCollectionName": "Books" }, "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Warning" } }, "AllowedHosts": "*" }
使用下列程式代碼將類別
BookStoreDatabaseSettings
新增至 Models 目錄:namespace BookStoreApi.Models; public class BookStoreDatabaseSettings { public string ConnectionString { get; set; } = null!; public string DatabaseName { get; set; } = null!; public string BooksCollectionName { get; set; } = null!; }
上述
BookStoreDatabaseSettings
類別是用來儲存appsettings.json
檔案的BookStoreDatabase
屬性值。 JSON 和 C# 屬性名稱以相同方式命名,以簡化對應程序。將下列醒目提示的程式碼新增至
Program.cs
:var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.Configure<BookStoreDatabaseSettings>( builder.Configuration.GetSection("BookStoreDatabase"));
在上述程式碼中,
appsettings.json
檔案的BookStoreDatabase
區段所繫結的設定執行個體已註冊在相依性注入 (DI) 容器中。 例如,BookStoreDatabaseSettings
物件的ConnectionString
屬性會填入BookStoreDatabase:ConnectionString
中的appsettings.json
屬性。在
Program.cs
的頂端新增下列程式碼,以解析BookStoreDatabaseSettings
參考:using BookStoreApi.Models;
新增 CRUD 作業服務
將 Services 目錄新增至專案根目錄。
使用下列程式代碼將類別
BooksService
新增至 Services 目錄:using BookStoreApi.Models; using Microsoft.Extensions.Options; using MongoDB.Driver; namespace BookStoreApi.Services; public class BooksService { private readonly IMongoCollection<Book> _booksCollection; public BooksService( IOptions<BookStoreDatabaseSettings> bookStoreDatabaseSettings) { var mongoClient = new MongoClient( bookStoreDatabaseSettings.Value.ConnectionString); var mongoDatabase = mongoClient.GetDatabase( bookStoreDatabaseSettings.Value.DatabaseName); _booksCollection = mongoDatabase.GetCollection<Book>( bookStoreDatabaseSettings.Value.BooksCollectionName); } public async Task<List<Book>> GetAsync() => await _booksCollection.Find(_ => true).ToListAsync(); public async Task<Book?> GetAsync(string id) => await _booksCollection.Find(x => x.Id == id).FirstOrDefaultAsync(); public async Task CreateAsync(Book newBook) => await _booksCollection.InsertOneAsync(newBook); public async Task UpdateAsync(string id, Book updatedBook) => await _booksCollection.ReplaceOneAsync(x => x.Id == id, updatedBook); public async Task RemoveAsync(string id) => await _booksCollection.DeleteOneAsync(x => x.Id == id); }
在前面的程式碼中,一個
BookStoreDatabaseSettings
執行個體是透過建構子注入從 DI 取得的。 此技術可讓您存取在appsettings.json
一節中新增的設定值。將下列醒目提示的程式碼新增至
Program.cs
:var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.Configure<BookStoreDatabaseSettings>( builder.Configuration.GetSection("BookStoreDatabase")); builder.Services.AddSingleton<BooksService>();
在上述程式碼中,
BooksService
類別要向 DI 註冊才能在取用類別中支援建構函式插入。 因為BooksService
直接依存於MongoClient
,所以 Singleton 服務存留期最適合。 根據官方的 Mongo 用戶端重複使用指導方針,應該將MongoClient
註冊為 DI 中的單例服務存留期。在
Program.cs
的頂端新增下列程式碼,以解析BooksService
參考:using BookStoreApi.Services;
BooksService
類別使用下列 MongoDB.Driver
成員來對資料庫執行 CRUD 作業:
MongoClient:讀取執行資料庫作業的伺服器實例。 此類別的建構函式會在 MongoDB 連接字串中提供:
public BooksService( IOptions<BookStoreDatabaseSettings> bookStoreDatabaseSettings) { var mongoClient = new MongoClient( bookStoreDatabaseSettings.Value.ConnectionString); var mongoDatabase = mongoClient.GetDatabase( bookStoreDatabaseSettings.Value.DatabaseName); _booksCollection = mongoDatabase.GetCollection<Book>( bookStoreDatabaseSettings.Value.BooksCollectionName); }
IMongoDatabase:代表執行作業的 Mongo 資料庫。 本教學課程使用 介面上的一般 GetCollection<TDocument>(collection) 方法,以存取特定集合中的數據。 呼叫此方法之後,針對集合執行 CRUD 作業。 在
GetCollection<TDocument>(collection)
方法呼叫中:-
collection
代表集合名稱。 -
TDocument
代表儲存在集合中的 CLR 物件類型。
-
GetCollection<TDocument>(collection)
會傳回代表集合的 MongoCollection 物件。 在此教程中,會在集合上調用下列方法:
- DeleteOneAsync:刪除符合所提供搜尋準則的單一檔。
- 找到<TDocument>:傳回集合中符合所提供搜尋準則的所有檔。
- InsertOneAsync:將提供的 物件插入為集合中的新檔。
- ReplaceOneAsync:將符合所提供搜尋準則的單一檔取代為提供的物件。
新增控制器
使用下列程式代碼將類別 BooksController
新增至 Controllers 目錄:
using BookStoreApi.Models;
using BookStoreApi.Services;
using Microsoft.AspNetCore.Mvc;
namespace BookStoreApi.Controllers;
[ApiController]
[Route("api/[controller]")]
public class BooksController : ControllerBase
{
private readonly BooksService _booksService;
public BooksController(BooksService booksService) =>
_booksService = booksService;
[HttpGet]
public async Task<List<Book>> Get() =>
await _booksService.GetAsync();
[HttpGet("{id:length(24)}")]
public async Task<ActionResult<Book>> Get(string id)
{
var book = await _booksService.GetAsync(id);
if (book is null)
{
return NotFound();
}
return book;
}
[HttpPost]
public async Task<IActionResult> Post(Book newBook)
{
await _booksService.CreateAsync(newBook);
return CreatedAtAction(nameof(Get), new { id = newBook.Id }, newBook);
}
[HttpPut("{id:length(24)}")]
public async Task<IActionResult> Update(string id, Book updatedBook)
{
var book = await _booksService.GetAsync(id);
if (book is null)
{
return NotFound();
}
updatedBook.Id = book.Id;
await _booksService.UpdateAsync(id, updatedBook);
return NoContent();
}
[HttpDelete("{id:length(24)}")]
public async Task<IActionResult> Delete(string id)
{
var book = await _booksService.GetAsync(id);
if (book is null)
{
return NotFound();
}
await _booksService.RemoveAsync(id);
return NoContent();
}
}
之前的 Web API 控制器。
- 使用
BooksService
類別來執行 CRUD 作業。 - 包含動作方法以支援 GET、POST、PUT 與 DELETE HTTP 要求。
- 在CreatedAtAction 動作方法中呼叫
Create
,以傳回 HTTP 201 回應。 對於可在伺服器上建立新資源的 HTTP POST 方法,其標準回應是狀態碼 201。CreatedAtAction
也會將Location
標頭新增至回應。Location
標頭指定新建書籍的 URI。
設定 JSON 序列化選項
有兩個細節需要變更,此變更涉及在「測試 Web API」章節中傳回的 JSON 回應。
- 屬性名稱的預設駝峰式大小寫應更改,使其符合 CLR 物件屬性的 Pascal 大小寫。
-
bookName
屬性應傳回為Name
。
為滿足上述需求,請進行下列變更:
在
Program.cs
中,將下列醒目提示的程式碼鏈結至AddControllers
方法呼叫:var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.Configure<BookStoreDatabaseSettings>( builder.Configuration.GetSection("BookStoreDatabase")); builder.Services.AddSingleton<BooksService>(); builder.Services.AddControllers() .AddJsonOptions( options => options.JsonSerializerOptions.PropertyNamingPolicy = null);
完成前述變更後,Web API 序列化 JSON 回應中屬性名稱即符合其對應的 CLR 物件類型屬性名稱。 例如,
Book
類別的Author
屬性會序列化為Author
,而非author
。在
Models/Book.cs
中,為BookName
屬性標註[JsonPropertyName]
屬性:[BsonElement("Name")] [JsonPropertyName("Name")] public string BookName { get; set; } = null!;
[JsonPropertyName]
的屬性值Name
代表 Web API 序列化 JSON 回應中的屬性名稱。在
Models/Book.cs
的頂端新增下列程式碼,以解析[JsonProperty]
屬性參考:using System.Text.Json.Serialization;
重複測試 Web API 一節中定義的步驟。 請注意 JSON 屬性名稱中的差異。
測試 Web API
本教學課程使用 端點總管和 .HTTP 檔案 來測試 API。
建置並執行應用程式。
在 [端點總管] 中,以滑鼠右鍵按兩下第一個 GET 端點
/api/books
,然後選取 [ 產生要求]。下列內容會新增至
BookStoreApi.http
檔案。 如果這是第一次產生要求,則會在專案根目錄中建立檔案。@BookStoreApi_HostAddress = https://localhost:<port> GET {{BookStoreApi_HostAddress}}/api/books ###
連接埠號碼應該已經設定為應用程式所使用的埠,例如
https://localhost:56874
。 如果不是這種情況,當您啟動應用程式時,可以在輸出視窗中找到您的埠號碼。選取新要求行上方的
GET
] 連結。GET 要求會傳送至應用程式,而回應會顯示在 [回應] 窗格中。
** 回應內容會顯示 JSON 結果,其中包含類似下列的書籍條目:
[ { "Id": "61a6058e6c43f32854e51f51", "Name": "Design Patterns", "Price": 54.93, "Category": "Computers", "Author": "Ralph Johnson" }, { "Id": "61a6058e6c43f32854e51f52", "Name": "Clean Code", "Price": 43.15, "Category": "Computers", "Author": "Robert C. Martin" } ]
若要取得單一書籍,請在
/api/books/{id}, params (string id)
中以滑鼠右鍵按一下 GET 端點,然後選取 產生要求。下列內容會附加至
BookStoreApi.http
檔案:@id=string GET {{BookStoreApi_HostAddress}}/api/books/{{id}} ###
以先前要求傳回的其中一個標識碼取代
id
變數,例如:@id="61a6058e6c43f32854e51f52" GET {{BookStoreApi_HostAddress}}/api/books/{{id}} ###
選取新要求行上方的
GET
] 連結。GET 要求會傳送至應用程式,而回應會顯示在 [回應] 窗格中。
回應主體會顯示類似下列的 JSON:
{ "Id": "61a6058e6c43f32854e51f52", "Name": "Clean Code", "Price": 43.15, "Category": "Computers", "Author": "Robert C. Martin" }
若要測試 POST 端點,請以滑鼠右鍵按兩下
/api/books
POST 端點,然後選取 [ 產生要求]。下列內容會新增至
BookStoreApi.http
檔案:POST {{BookStoreApi_HostAddress}}/api/books Content-Type: application/json { //Book } ###
將書籍評論替換為 book 物件,作為 JSON 請求的主體:
POST {{BookStoreApi_HostAddress}}/api/books Content-Type: application/json { "Name": "The Pragmatic Programmer", "Price": 49.99, "Category": "Computers", "Author": "Andy Hunt" } ###
選取要求行上方的
POST
] 連結。POST 要求會傳送至應用程式,而響應會顯示在 [ 回應 ] 窗格中。 回應應該包含新建立的書籍及其指定的ID。
最後,若要刪除書籍,請以滑鼠右鍵按兩下
/api/books/{id}, params (string id)
DELETE 端點,然後選取 [ 產生要求]。下列內容會附加至
BookStoreApi.http
檔案:DELETE {{BookStoreApi_HostAddress}}/api/Books/{{id}} ###
將
id
變數替換為之前的請求返回的其中一個識別碼,然後點擊 [傳送要求]。 例如:DELETE {{BookStoreApi_HostAddress}}/api/Books/67f417517ce1b36aeab71236 ###
將驗證支援新增至 Web API
ASP.NET Core Identity 會將使用者介面 (UI) 登入功能新增至 ASP.NET Core Web 應用程式。 若要保護 Web API 和 SPA,請使用下列其中一項:
- Microsoft Entra 身份識別
- Azure Active Directory B2C (Azure AD B2C)
- Duende Identity 伺服器
Duende Identity 伺服器是適用於 ASP.NET Core 的 OpenID Connect 和 OAuth 2.0 架構。 Duende Identity 伺服器會啟用下列安全性功能:
- 驗證即服務 (AaaS)
- 多個應用程式類型的單一登入/登出 (SSO)
- API 的存取控制
- 同盟閘道
重要
Duende Software 可能會要求您支付使用 Duende Identity 伺服器的授權費用。 如需詳細資訊,請參閱 從 .NET 5 中的 ASP.NET Core 移轉至 .NET 6。
如需詳細資訊,請參閱 Duende 伺服器檔(Duende Identity Software 網站)。
其他資源
本教學課程會建立 Web API,以在 MongoDB NoSQL 資料庫上執行建立、讀取、更新和刪除 (CRUD) 作業。
在本教學課程中,您會了解如何:
- 設定 MongoDB
- 建立 MongoDB 資料庫
- 定義 MongoDB 集合與結構描述
- 從 Web API 執行 MongoDB CRUD 作業
- 自訂 JSON 序列化
必要條件
具有 ASP.NET 和 Web 開發工作負載的 Visual Studio 2022。
設定 MongoDB
從開發機器上的任何位置啟用 MongoDB 和 Mongo DB 殼層存取 (Windows/Linux/macOS):
下載並安裝 MongoDB Shell:
- macOS/Linux: 選擇要擷取 MongoDB Shell 的目錄。 將針對
mongosh
產生的路徑新增至PATH
環境變數。 - Windows:MongoDB Shell (mongosh.exe) 安裝在 C:\Users\<user>\AppData\Local\Programs\mongosh。 將針對
mongosh.exe
產生的路徑新增至PATH
環境變數。
- macOS/Linux: 選擇要擷取 MongoDB Shell 的目錄。 將針對
下載並安裝 MongoDB:
- macOS/Linux:確認已安裝 MongoDB 的目錄,通常是在 /usr/local/mongodb 中。 將針對
mongodb
產生的路徑新增至PATH
環境變數。 - Windows:MongoDB 預設會安裝在 C:\Program Files\MongoDB 。 將 C:\Program Files\MongoDB\Server\<version_number>\bin 新增至
PATH
環境變數。
- macOS/Linux:確認已安裝 MongoDB 的目錄,通常是在 /usr/local/mongodb 中。 將針對
選擇資料記憶體目錄: 選取開發電腦上的目錄來儲存資料。 若該目錄不存在,請建立它。 MongoDB 殼層不會建立新目錄:
- macOS/Linux: 例如
/usr/local/var/mongodb
。 - Windows: 例如
C:\\BooksData
。
- macOS/Linux: 例如
在 OS 命令殼層 (非 MongoDB 殼層) 中,使用下列命令在預設連接埠 27017 上連線到 MongoDB。 將
<data_directory_path>
取代為上一個步驟中所選擇的目錄。mongod --dbpath <data_directory_path>
在下列步驟中使用先前安裝的 MongoDB 殼層來建立資料庫、建立集合及儲存文件。 如需 MongoDB 殼層命令的詳細資訊,請參閱 mongosh
。
啟動
mongosh.exe
,或在命令殼層中執行下列命令,以開啟 MongoDB 命令殼層實例:mongosh
在命令殼層中,執行下列命令介面以連線到預設測試資料庫:
use BookStore
如果 BookStore 不存在,就會建立名為 BookStore 的資料庫。 若該資料庫存在,會開啟其連線進行交易。
使用下列命令建立
Books
集合:db.createCollection('Books')
顯示的結果如下:
{ "ok" : 1 }
使用下列命令為
Books
集合定義結構描述並插入兩份文件:db.Books.insertMany([{ "Name": "Design Patterns", "Price": 54.93, "Category": "Computers", "Author": "Ralph Johnson" }, { "Name": "Clean Code", "Price": 43.15, "Category": "Computers","Author": "Robert C. Martin" }])
會顯示類似下列的結果:
{ "acknowledged" : true, "insertedIds" : [ ObjectId("61a6058e6c43f32854e51f51"), ObjectId("61a6058e6c43f32854e51f52") ] }
注意
上述結果中顯示的
ObjectId
,不符合命令列介面中顯示的結果。使用下列命令檢視資料庫中的文件:
db.Books.find().pretty()
會顯示類似下列的結果:
{ "_id" : ObjectId("61a6058e6c43f32854e51f51"), "Name" : "Design Patterns", "Price" : 54.93, "Category" : "Computers", "Author" : "Ralph Johnson" } { "_id" : ObjectId("61a6058e6c43f32854e51f52"), "Name" : "Clean Code", "Price" : 43.15, "Category" : "Computers", "Author" : "Robert C. Martin" }
結構描述會為每份文件新增自動生成的
_id
屬性 (類型ObjectId
)。
建立 ASP.NET Core Web API 專案
移至 [ 檔案>新>專案]。
選取 [ASP.NET Core Web API] 專案型別,然後選取 [下一步]。
將專案命名為 BookStoreApi,然後選取 [ 下一步]。
選取 [.NET 8.0 (長期支援)] 架構,然後選取 [建立]。
在 [套件管理員主控台] 視窗中,瀏覽到專案根目錄。 執行下列命令以安裝適用於 MongoDB 的 .NET 驅動程式:
Install-Package MongoDB.Driver
新增實體模型
將 Models 目錄新增至專案根目錄。
使用下列程式代碼將類別
Book
新增至 Models 目錄:using MongoDB.Bson; using MongoDB.Bson.Serialization.Attributes; namespace BookStoreApi.Models; public class Book { [BsonId] [BsonRepresentation(BsonType.ObjectId)] public string? Id { get; set; } [BsonElement("Name")] public string BookName { get; set; } = null!; public decimal Price { get; set; } public string Category { get; set; } = null!; public string Author { get; set; } = null!; }
在上述類別中,
Id
屬性為:- 將 Common Language Runtime (CLR) 物件對應到 MongoDB 集合所需。
- 使用
[BsonId]
標註,以讓此屬性成為文件的主索引鍵。 - 加上
[BsonRepresentation(BsonType.ObjectId)]
批註,以允許將參數傳遞為型別string
,而非ObjectId結構。 Mongo 會處理從string
轉換到ObjectId
的作業。
BookName
屬性會使用[BsonElement]
屬性標註。Name
的屬性值代表 MongoDB 集合中的屬性名稱。
新增組態模型
將下列資料庫設定值新增至
appsettings.json
:{ "BookStoreDatabase": { "ConnectionString": "mongodb://localhost:27017", "DatabaseName": "BookStore", "BooksCollectionName": "Books" }, "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Warning" } }, "AllowedHosts": "*" }
使用下列程式代碼將類別
BookStoreDatabaseSettings
新增至 Models 目錄:namespace BookStoreApi.Models; public class BookStoreDatabaseSettings { public string ConnectionString { get; set; } = null!; public string DatabaseName { get; set; } = null!; public string BooksCollectionName { get; set; } = null!; }
上述
BookStoreDatabaseSettings
類別是用來儲存appsettings.json
檔案的BookStoreDatabase
屬性值。 JSON 和 C# 屬性名稱以相同方式命名,以簡化對應程序。將下列醒目提示的程式碼新增至
Program.cs
:var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.Configure<BookStoreDatabaseSettings>( builder.Configuration.GetSection("BookStoreDatabase"));
在上述程式碼中,
appsettings.json
檔案的BookStoreDatabase
區段所繫結的設定執行個體已註冊在相依性注入 (DI) 容器中。 例如,BookStoreDatabaseSettings
物件的ConnectionString
屬性會填入BookStoreDatabase:ConnectionString
中的appsettings.json
屬性。在
Program.cs
的頂端新增下列程式碼,以解析BookStoreDatabaseSettings
參考:using BookStoreApi.Models;
新增 CRUD 作業服務
將 Services 目錄新增至專案根目錄。
使用下列程式代碼將類別
BooksService
新增至 Services 目錄:using BookStoreApi.Models; using Microsoft.Extensions.Options; using MongoDB.Driver; namespace BookStoreApi.Services; public class BooksService { private readonly IMongoCollection<Book> _booksCollection; public BooksService( IOptions<BookStoreDatabaseSettings> bookStoreDatabaseSettings) { var mongoClient = new MongoClient( bookStoreDatabaseSettings.Value.ConnectionString); var mongoDatabase = mongoClient.GetDatabase( bookStoreDatabaseSettings.Value.DatabaseName); _booksCollection = mongoDatabase.GetCollection<Book>( bookStoreDatabaseSettings.Value.BooksCollectionName); } public async Task<List<Book>> GetAsync() => await _booksCollection.Find(_ => true).ToListAsync(); public async Task<Book?> GetAsync(string id) => await _booksCollection.Find(x => x.Id == id).FirstOrDefaultAsync(); public async Task CreateAsync(Book newBook) => await _booksCollection.InsertOneAsync(newBook); public async Task UpdateAsync(string id, Book updatedBook) => await _booksCollection.ReplaceOneAsync(x => x.Id == id, updatedBook); public async Task RemoveAsync(string id) => await _booksCollection.DeleteOneAsync(x => x.Id == id); }
在前面的程式碼中,一個
BookStoreDatabaseSettings
執行個體是透過建構子注入從 DI 取得的。 此技術可讓您存取在appsettings.json
一節中新增的設定值。將下列醒目提示的程式碼新增至
Program.cs
:var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.Configure<BookStoreDatabaseSettings>( builder.Configuration.GetSection("BookStoreDatabase")); builder.Services.AddSingleton<BooksService>();
在上述程式碼中,
BooksService
類別要向 DI 註冊才能在取用類別中支援建構函式插入。 因為BooksService
直接依存於MongoClient
,所以 Singleton 服務存留期最適合。 根據官方的 Mongo 用戶端重複使用指導方針,應該將MongoClient
註冊為 DI 中的單例服務存留期。在
Program.cs
的頂端新增下列程式碼,以解析BooksService
參考:using BookStoreApi.Services;
BooksService
類別使用下列 MongoDB.Driver
成員來對資料庫執行 CRUD 作業:
MongoClient:讀取執行資料庫作業的伺服器實例。 此類別的建構函式會在 MongoDB 連接字串中提供:
public BooksService( IOptions<BookStoreDatabaseSettings> bookStoreDatabaseSettings) { var mongoClient = new MongoClient( bookStoreDatabaseSettings.Value.ConnectionString); var mongoDatabase = mongoClient.GetDatabase( bookStoreDatabaseSettings.Value.DatabaseName); _booksCollection = mongoDatabase.GetCollection<Book>( bookStoreDatabaseSettings.Value.BooksCollectionName); }
IMongoDatabase:代表執行作業的 Mongo 資料庫。 本教學課程使用 介面上的一般 GetCollection<TDocument>(collection) 方法,以存取特定集合中的數據。 呼叫此方法之後,針對集合執行 CRUD 作業。 在
GetCollection<TDocument>(collection)
方法呼叫中:-
collection
代表集合名稱。 -
TDocument
代表儲存在集合中的 CLR 物件類型。
-
GetCollection<TDocument>(collection)
會傳回代表集合的 MongoCollection 物件。 在此教程中,會在集合上調用下列方法:
- DeleteOneAsync:刪除符合所提供搜尋準則的單一檔。
- 找到<TDocument>:傳回集合中符合所提供搜尋準則的所有檔。
- InsertOneAsync:將提供的 物件插入為集合中的新檔。
- ReplaceOneAsync:將符合所提供搜尋準則的單一檔取代為提供的物件。
新增控制器
使用下列程式代碼將類別 BooksController
新增至 Controllers 目錄:
using BookStoreApi.Models;
using BookStoreApi.Services;
using Microsoft.AspNetCore.Mvc;
namespace BookStoreApi.Controllers;
[ApiController]
[Route("api/[controller]")]
public class BooksController : ControllerBase
{
private readonly BooksService _booksService;
public BooksController(BooksService booksService) =>
_booksService = booksService;
[HttpGet]
public async Task<List<Book>> Get() =>
await _booksService.GetAsync();
[HttpGet("{id:length(24)}")]
public async Task<ActionResult<Book>> Get(string id)
{
var book = await _booksService.GetAsync(id);
if (book is null)
{
return NotFound();
}
return book;
}
[HttpPost]
public async Task<IActionResult> Post(Book newBook)
{
await _booksService.CreateAsync(newBook);
return CreatedAtAction(nameof(Get), new { id = newBook.Id }, newBook);
}
[HttpPut("{id:length(24)}")]
public async Task<IActionResult> Update(string id, Book updatedBook)
{
var book = await _booksService.GetAsync(id);
if (book is null)
{
return NotFound();
}
updatedBook.Id = book.Id;
await _booksService.UpdateAsync(id, updatedBook);
return NoContent();
}
[HttpDelete("{id:length(24)}")]
public async Task<IActionResult> Delete(string id)
{
var book = await _booksService.GetAsync(id);
if (book is null)
{
return NotFound();
}
await _booksService.RemoveAsync(id);
return NoContent();
}
}
之前的 Web API 控制器。
- 使用
BooksService
類別來執行 CRUD 作業。 - 包含動作方法以支援 GET、POST、PUT 與 DELETE HTTP 要求。
- 在CreatedAtAction 動作方法中呼叫
Create
,以傳回 HTTP 201 回應。 對於可在伺服器上建立新資源的 HTTP POST 方法,其標準回應是狀態碼 201。CreatedAtAction
也會將Location
標頭新增至回應。Location
標頭指定新建書籍的 URI。
測試 Web API
建置並執行應用程式。
瀏覽至
https://localhost:<port>/api/books
,其中的<port>
是應用程式自動指派的連接埠號碼,以測試控制器的無參數Get
動作方法。 類似下列的 JSON 回應隨即會顯示:[ { "id": "61a6058e6c43f32854e51f51", "bookName": "Design Patterns", "price": 54.93, "category": "Computers", "author": "Ralph Johnson" }, { "id": "61a6058e6c43f32854e51f52", "bookName": "Clean Code", "price": 43.15, "category": "Computers", "author": "Robert C. Martin" } ]
巡覽至
https://localhost:<port>/api/books/{id here}
,測試控制器的多載Get
動作方法。 類似下列的 JSON 回應隨即會顯示:{ "id": "61a6058e6c43f32854e51f52", "bookName": "Clean Code", "price": 43.15, "category": "Computers", "author": "Robert C. Martin" }
設定 JSON 序列化選項
有兩個細節需要變更,此變更涉及在「測試 Web API」章節中傳回的 JSON 回應。
- 屬性名稱的預設駝峰式大小寫應更改,使其符合 CLR 物件屬性的 Pascal 大小寫。
-
bookName
屬性應傳回為Name
。
為滿足上述需求,請進行下列變更:
在
Program.cs
中,將下列醒目提示的程式碼鏈結至AddControllers
方法呼叫:var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.Configure<BookStoreDatabaseSettings>( builder.Configuration.GetSection("BookStoreDatabase")); builder.Services.AddSingleton<BooksService>(); builder.Services.AddControllers() .AddJsonOptions( options => options.JsonSerializerOptions.PropertyNamingPolicy = null);
完成前述變更後,Web API 序列化 JSON 回應中屬性名稱即符合其對應的 CLR 物件類型屬性名稱。 例如,
Book
類別的Author
屬性會序列化為Author
,而非author
。在
Models/Book.cs
中,為BookName
屬性標註[JsonPropertyName]
屬性:[BsonElement("Name")] [JsonPropertyName("Name")] public string BookName { get; set; } = null!;
[JsonPropertyName]
的屬性值Name
代表 Web API 序列化 JSON 回應中的屬性名稱。在
Models/Book.cs
的頂端新增下列程式碼,以解析[JsonProperty]
屬性參考:using System.Text.Json.Serialization;
重複測試 Web API 一節中定義的步驟。 請注意 JSON 屬性名稱中的差異。
將驗證支援新增至 Web API
ASP.NET Core Identity 會將使用者介面 (UI) 登入功能新增至 ASP.NET Core Web 應用程式。 若要保護 Web API 和 SPA,請使用下列其中一項:
- Microsoft Entra 身份識別
- Azure Active Directory B2C (Azure AD B2C)
- Duende Identity 伺服器
Duende Identity 伺服器是適用於 ASP.NET Core 的 OpenID Connect 和 OAuth 2.0 架構。 Duende Identity 伺服器會啟用下列安全性功能:
- 驗證即服務 (AaaS)
- 多個應用程式類型的單一登入/登出 (SSO)
- API 的存取控制
- 同盟閘道
重要
Duende Software 可能會要求您支付使用 Duende Identity 伺服器的授權費用。 如需詳細資訊,請參閱 從 .NET 5 中的 ASP.NET Core 移轉至 .NET 6。
如需詳細資訊,請參閱 Duende 伺服器檔(Duende Identity Software 網站)。
其他資源
本教學課程會建立 Web API,以在 MongoDB NoSQL 資料庫上執行建立、讀取、更新和刪除 (CRUD) 作業。
在本教學課程中,您會了解如何:
- 設定 MongoDB
- 建立 MongoDB 資料庫
- 定義 MongoDB 集合與結構描述
- 從 Web API 執行 MongoDB CRUD 作業
- 自訂 JSON 序列化
必要條件
具有 ASP.NET 和 Web 開發工作負載的 Visual Studio 2022。
設定 MongoDB
從開發機器上的任何位置啟用 MongoDB 和 Mongo DB 殼層存取:
在 Windows 上,MongoDB 預設會安裝在 C:\Program Files\MongoDB 。 將 C:\Program Files\MongoDB\Server\<version_number>\bin 新增至
PATH
環境變數。下載 MongoDB Shell,然後選擇一個目錄以將其解壓縮。 將針對
mongosh.exe
產生的路徑新增至PATH
環境變數。選擇開發機器上的目錄來存放資料。 例如, Windows 上的 C:\BooksData 。 若該目錄不存在,請建立它。 mongo Shell 不會建立新目錄。
在 OS 命令殼層 (非 MongoDB 殼層) 中,使用下列命令在預設連接埠 27017 上連線到 MongoDB。 將
<data_directory_path>
取代為上一個步驟中所選擇的目錄。mongod --dbpath <data_directory_path>
在下列步驟中使用先前安裝的 MongoDB 殼層來建立資料庫、建立集合及儲存文件。 如需 MongoDB 殼層命令的詳細資訊,請參閱 mongosh
。
啟動
mongosh.exe
,或在命令殼層中執行下列命令,以開啟 MongoDB 命令殼層實例:mongosh
在命令殼層中,執行下列命令介面以連線到預設測試資料庫:
use BookStore
如果 BookStore 不存在,就會建立名為 BookStore 的資料庫。 若該資料庫存在,會開啟其連線進行交易。
使用下列命令建立
Books
集合:db.createCollection('Books')
顯示的結果如下:
{ "ok" : 1 }
使用下列命令為
Books
集合定義結構描述並插入兩份文件:db.Books.insertMany([{ "Name": "Design Patterns", "Price": 54.93, "Category": "Computers", "Author": "Ralph Johnson" }, { "Name": "Clean Code", "Price": 43.15, "Category": "Computers","Author": "Robert C. Martin" }])
會顯示類似下列的結果:
{ "acknowledged" : true, "insertedIds" : [ ObjectId("61a6058e6c43f32854e51f51"), ObjectId("61a6058e6c43f32854e51f52") ] }
注意
上述結果中顯示的
ObjectId
,不符合命令列介面中顯示的結果。使用下列命令檢視資料庫中的文件:
db.Books.find().pretty()
會顯示類似下列的結果:
{ "_id" : ObjectId("61a6058e6c43f32854e51f51"), "Name" : "Design Patterns", "Price" : 54.93, "Category" : "Computers", "Author" : "Ralph Johnson" } { "_id" : ObjectId("61a6058e6c43f32854e51f52"), "Name" : "Clean Code", "Price" : 43.15, "Category" : "Computers", "Author" : "Robert C. Martin" }
結構描述會為每份文件新增自動生成的
_id
屬性 (類型ObjectId
)。
建立 ASP.NET Core Web API 專案
移至 [ 檔案>新>專案]。
選取 [ASP.NET Core Web API] 專案型別,然後選取 [下一步]。
將專案命名為 BookStoreApi,然後選取 [ 下一步]。
選取 [.NET 7.0 (標準期間支援)] 架構,然後選取 [建立]。
從 [工具] 功能表中,選取 [NuGet 套件管理員]> [套件管理員主控台]。
在 [套件管理員主控台] 視窗中,瀏覽到專案根目錄。 執行下列命令以安裝適用於 MongoDB 的 .NET 驅動程式:
Install-Package MongoDB.Driver
新增實體模型
將 Models 目錄新增至專案根目錄。
使用下列程式代碼將類別
Book
新增至 Models 目錄:using MongoDB.Bson; using MongoDB.Bson.Serialization.Attributes; namespace BookStoreApi.Models; public class Book { [BsonId] [BsonRepresentation(BsonType.ObjectId)] public string? Id { get; set; } [BsonElement("Name")] public string BookName { get; set; } = null!; public decimal Price { get; set; } public string Category { get; set; } = null!; public string Author { get; set; } = null!; }
在上述類別中,
Id
屬性為:- 將 Common Language Runtime (CLR) 物件對應到 MongoDB 集合所需。
- 使用
[BsonId]
標註,以讓此屬性成為文件的主索引鍵。 - 加上
[BsonRepresentation(BsonType.ObjectId)]
批註,以允許將參數傳遞為型別string
,而非ObjectId結構。 Mongo 會處理從string
轉換到ObjectId
的作業。
BookName
屬性會使用[BsonElement]
屬性標註。Name
的屬性值代表 MongoDB 集合中的屬性名稱。
新增組態模型
將下列資料庫設定值新增至
appsettings.json
:{ "BookStoreDatabase": { "ConnectionString": "mongodb://localhost:27017", "DatabaseName": "BookStore", "BooksCollectionName": "Books" }, "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Warning" } }, "AllowedHosts": "*" }
使用下列程式代碼將類別
BookStoreDatabaseSettings
新增至 Models 目錄:namespace BookStoreApi.Models; public class BookStoreDatabaseSettings { public string ConnectionString { get; set; } = null!; public string DatabaseName { get; set; } = null!; public string BooksCollectionName { get; set; } = null!; }
上述
BookStoreDatabaseSettings
類別是用來儲存appsettings.json
檔案的BookStoreDatabase
屬性值。 JSON 和 C# 屬性名稱以相同方式命名,以簡化對應程序。將下列醒目提示的程式碼新增至
Program.cs
:var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.Configure<BookStoreDatabaseSettings>( builder.Configuration.GetSection("BookStoreDatabase"));
在上述程式碼中,
appsettings.json
檔案的BookStoreDatabase
區段所繫結的設定執行個體已註冊在相依性注入 (DI) 容器中。 例如,BookStoreDatabaseSettings
物件的ConnectionString
屬性會填入BookStoreDatabase:ConnectionString
中的appsettings.json
屬性。在
Program.cs
的頂端新增下列程式碼,以解析BookStoreDatabaseSettings
參考:using BookStoreApi.Models;
新增 CRUD 作業服務
將 Services 目錄新增至專案根目錄。
使用下列程式代碼將類別
BooksService
新增至 Services 目錄:using BookStoreApi.Models; using Microsoft.Extensions.Options; using MongoDB.Driver; namespace BookStoreApi.Services; public class BooksService { private readonly IMongoCollection<Book> _booksCollection; public BooksService( IOptions<BookStoreDatabaseSettings> bookStoreDatabaseSettings) { var mongoClient = new MongoClient( bookStoreDatabaseSettings.Value.ConnectionString); var mongoDatabase = mongoClient.GetDatabase( bookStoreDatabaseSettings.Value.DatabaseName); _booksCollection = mongoDatabase.GetCollection<Book>( bookStoreDatabaseSettings.Value.BooksCollectionName); } public async Task<List<Book>> GetAsync() => await _booksCollection.Find(_ => true).ToListAsync(); public async Task<Book?> GetAsync(string id) => await _booksCollection.Find(x => x.Id == id).FirstOrDefaultAsync(); public async Task CreateAsync(Book newBook) => await _booksCollection.InsertOneAsync(newBook); public async Task UpdateAsync(string id, Book updatedBook) => await _booksCollection.ReplaceOneAsync(x => x.Id == id, updatedBook); public async Task RemoveAsync(string id) => await _booksCollection.DeleteOneAsync(x => x.Id == id); }
在前面的程式碼中,一個
BookStoreDatabaseSettings
執行個體是透過建構子注入從 DI 取得的。 此技術可讓您存取在appsettings.json
一節中新增的設定值。將下列醒目提示的程式碼新增至
Program.cs
:var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.Configure<BookStoreDatabaseSettings>( builder.Configuration.GetSection("BookStoreDatabase")); builder.Services.AddSingleton<BooksService>();
在上述程式碼中,
BooksService
類別要向 DI 註冊才能在取用類別中支援建構函式插入。 因為BooksService
直接依存於MongoClient
,所以 Singleton 服務存留期最適合。 根據官方的 Mongo 用戶端重複使用指導方針,應該將MongoClient
註冊為 DI 中的單例服務存留期。在
Program.cs
的頂端新增下列程式碼,以解析BooksService
參考:using BookStoreApi.Services;
BooksService
類別使用下列 MongoDB.Driver
成員來對資料庫執行 CRUD 作業:
MongoClient:讀取執行資料庫作業的伺服器實例。 此類別的建構函式會被賦予一個 MongoDB 連接字串:
public BooksService( IOptions<BookStoreDatabaseSettings> bookStoreDatabaseSettings) { var mongoClient = new MongoClient( bookStoreDatabaseSettings.Value.ConnectionString); var mongoDatabase = mongoClient.GetDatabase( bookStoreDatabaseSettings.Value.DatabaseName); _booksCollection = mongoDatabase.GetCollection<Book>( bookStoreDatabaseSettings.Value.BooksCollectionName); }
IMongoDatabase:代表執行作業的 Mongo 資料庫。 本教學課程使用 介面上的一般 GetCollection<TDocument>(collection) 方法,以存取特定集合中的數據。 呼叫此方法之後,針對集合執行 CRUD 作業。 在
GetCollection<TDocument>(collection)
方法呼叫中:-
collection
代表集合名稱。 -
TDocument
代表儲存在集合中的 CLR 物件類型。
-
GetCollection<TDocument>(collection)
會傳回代表集合的 MongoCollection 物件。 在此教程中,會在集合上調用下列方法:
- DeleteOneAsync:刪除符合所提供搜尋準則的單一檔。
- 找到<TDocument>:傳回集合中符合所提供搜尋準則的所有檔。
- InsertOneAsync:將提供的 物件插入為集合中的新檔。
- ReplaceOneAsync:將符合所提供搜尋準則的單一檔取代為提供的物件。
新增控制器
使用下列程式代碼將類別 BooksController
新增至 Controllers 目錄:
using BookStoreApi.Models;
using BookStoreApi.Services;
using Microsoft.AspNetCore.Mvc;
namespace BookStoreApi.Controllers;
[ApiController]
[Route("api/[controller]")]
public class BooksController : ControllerBase
{
private readonly BooksService _booksService;
public BooksController(BooksService booksService) =>
_booksService = booksService;
[HttpGet]
public async Task<List<Book>> Get() =>
await _booksService.GetAsync();
[HttpGet("{id:length(24)}")]
public async Task<ActionResult<Book>> Get(string id)
{
var book = await _booksService.GetAsync(id);
if (book is null)
{
return NotFound();
}
return book;
}
[HttpPost]
public async Task<IActionResult> Post(Book newBook)
{
await _booksService.CreateAsync(newBook);
return CreatedAtAction(nameof(Get), new { id = newBook.Id }, newBook);
}
[HttpPut("{id:length(24)}")]
public async Task<IActionResult> Update(string id, Book updatedBook)
{
var book = await _booksService.GetAsync(id);
if (book is null)
{
return NotFound();
}
updatedBook.Id = book.Id;
await _booksService.UpdateAsync(id, updatedBook);
return NoContent();
}
[HttpDelete("{id:length(24)}")]
public async Task<IActionResult> Delete(string id)
{
var book = await _booksService.GetAsync(id);
if (book is null)
{
return NotFound();
}
await _booksService.RemoveAsync(id);
return NoContent();
}
}
之前的 Web API 控制器。
- 使用
BooksService
類別來執行 CRUD 作業。 - 包含動作方法以支援 GET、POST、PUT 與 DELETE HTTP 要求。
- 在CreatedAtAction 動作方法中呼叫
Create
,以傳回 HTTP 201 回應。 對於可在伺服器上建立新資源的 HTTP POST 方法,其標準回應是狀態碼 201。CreatedAtAction
也會將Location
標頭新增至回應。Location
標頭指定新建書籍的 URI。
測試 Web API
建置並執行應用程式。
瀏覽至
https://localhost:<port>/api/books
,其中的<port>
是應用程式自動指派的連接埠號碼,以測試控制器的無參數Get
動作方法。 類似下列的 JSON 回應隨即會顯示:[ { "id": "61a6058e6c43f32854e51f51", "bookName": "Design Patterns", "price": 54.93, "category": "Computers", "author": "Ralph Johnson" }, { "id": "61a6058e6c43f32854e51f52", "bookName": "Clean Code", "price": 43.15, "category": "Computers", "author": "Robert C. Martin" } ]
巡覽至
https://localhost:<port>/api/books/{id here}
,測試控制器的多載Get
動作方法。 類似下列的 JSON 回應隨即會顯示:{ "id": "61a6058e6c43f32854e51f52", "bookName": "Clean Code", "price": 43.15, "category": "Computers", "author": "Robert C. Martin" }
設定 JSON 序列化選項
有兩個細節需要變更,此變更涉及在「測試 Web API」章節中傳回的 JSON 回應。
- 屬性名稱的預設駝峰式大小寫應更改,使其符合 CLR 物件屬性的 Pascal 大小寫。
-
bookName
屬性應傳回為Name
。
為滿足上述需求,請進行下列變更:
在
Program.cs
中,將下列醒目提示的程式碼鏈結至AddControllers
方法呼叫:var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.Configure<BookStoreDatabaseSettings>( builder.Configuration.GetSection("BookStoreDatabase")); builder.Services.AddSingleton<BooksService>(); builder.Services.AddControllers() .AddJsonOptions( options => options.JsonSerializerOptions.PropertyNamingPolicy = null);
完成前述變更後,Web API 序列化 JSON 回應中屬性名稱即符合其對應的 CLR 物件類型屬性名稱。 例如,
Book
類別的Author
屬性會序列化為Author
,而非author
。在
Models/Book.cs
中,為BookName
屬性標註[JsonPropertyName]
屬性:[BsonElement("Name")] [JsonPropertyName("Name")] public string BookName { get; set; } = null!;
[JsonPropertyName]
的屬性值Name
代表 Web API 序列化 JSON 回應中的屬性名稱。在
Models/Book.cs
的頂端新增下列程式碼,以解析[JsonProperty]
屬性參考:using System.Text.Json.Serialization;
重複測試 Web API 一節中定義的步驟。 請注意 JSON 屬性名稱中的差異。
將驗證支援新增至 Web API
ASP.NET Core Identity 會將使用者介面 (UI) 登入功能新增至 ASP.NET Core Web 應用程式。 若要保護 Web API 和 SPA,請使用下列其中一項:
- Microsoft Entra 身份識別
- Azure Active Directory B2C (Azure AD B2C)
- Duende Identity 伺服器
Duende Identity 伺服器是適用於 ASP.NET Core 的 OpenID Connect 和 OAuth 2.0 架構。 Duende Identity 伺服器會啟用下列安全性功能:
- 驗證即服務 (AaaS)
- 多個應用程式類型的單一登入/登出 (SSO)
- API 的存取控制
- 同盟閘道
重要
Duende Software 可能會要求您支付使用 Duende Identity 伺服器的授權費用。 如需詳細資訊,請參閱 從 .NET 5 中的 ASP.NET Core 移轉至 .NET 6。
如需詳細資訊,請參閱 Duende 伺服器檔(Duende Identity Software 網站)。
其他資源
本教學課程會建立 Web API,以在 MongoDB NoSQL 資料庫上執行建立、讀取、更新和刪除 (CRUD) 作業。
在本教學課程中,您會了解如何:
- 設定 MongoDB
- 建立 MongoDB 資料庫
- 定義 MongoDB 集合與結構描述
- 從 Web API 執行 MongoDB CRUD 作業
- 自訂 JSON 序列化
必要條件
- 具有 ASP.NET 和 Web 開發工作負載的 Visual Studio 2022。
- .NET 6 SDK
設定 MongoDB
從開發機器上的任何位置啟用 MongoDB 和 Mongo DB 殼層存取:
在 Windows 上,MongoDB 預設會安裝在 C:\Program Files\MongoDB 。 將 C:\Program Files\MongoDB\Server\<version_number>\bin 新增至
PATH
環境變數。下載 MongoDB Shell,然後選擇一個目錄以將其解壓縮。 將針對
mongosh.exe
產生的路徑新增至PATH
環境變數。選擇開發機器上的目錄來存放資料。 例如, Windows 上的 C:\BooksData 。 若該目錄不存在,請建立它。 mongo Shell 不會建立新目錄。
在 OS 命令殼層 (非 MongoDB 殼層) 中,使用下列命令在預設連接埠 27017 上連線到 MongoDB。 將
<data_directory_path>
取代為上一個步驟中所選擇的目錄。mongod --dbpath <data_directory_path>
在下列步驟中使用先前安裝的 MongoDB 殼層來建立資料庫、建立集合及儲存文件。 如需 MongoDB 殼層命令的詳細資訊,請參閱 mongosh
。
啟動
mongosh.exe
,或在命令殼層中執行下列命令,以開啟 MongoDB 命令殼層實例:mongosh
在命令殼層中,執行下列命令介面以連線到預設測試資料庫:
use BookStore
如果 BookStore 不存在,就會建立名為 BookStore 的資料庫。 若該資料庫存在,會開啟其連線進行交易。
使用下列命令建立
Books
集合:db.createCollection('Books')
顯示的結果如下:
{ "ok" : 1 }
使用下列命令為
Books
集合定義結構描述並插入兩份文件:db.Books.insertMany([{ "Name": "Design Patterns", "Price": 54.93, "Category": "Computers", "Author": "Ralph Johnson" }, { "Name": "Clean Code", "Price": 43.15, "Category": "Computers","Author": "Robert C. Martin" }])
會顯示類似下列的結果:
{ "acknowledged" : true, "insertedIds" : [ ObjectId("61a6058e6c43f32854e51f51"), ObjectId("61a6058e6c43f32854e51f52") ] }
注意
上述結果中顯示的
ObjectId
,不符合命令列介面中顯示的結果。使用下列命令檢視資料庫中的文件:
db.Books.find().pretty()
會顯示類似下列的結果:
{ "_id" : ObjectId("61a6058e6c43f32854e51f51"), "Name" : "Design Patterns", "Price" : 54.93, "Category" : "Computers", "Author" : "Ralph Johnson" } { "_id" : ObjectId("61a6058e6c43f32854e51f52"), "Name" : "Clean Code", "Price" : 43.15, "Category" : "Computers", "Author" : "Robert C. Martin" }
結構描述會為每份文件新增自動生成的
_id
屬性 (類型ObjectId
)。
建立 ASP.NET Core Web API 專案
移至 [ 檔案>新>專案]。
選取 [ASP.NET Core Web API] 專案型別,然後選取 [下一步]。
將專案命名為 BookStoreApi,然後選取 [ 下一步]。
選取 [.NET 6.0 (長期支援)] 架構,然後選取 [建立]。
在 [套件管理員主控台] 視窗中,瀏覽到專案根目錄。 執行下列命令以安裝適用於 MongoDB 的 .NET 驅動程式:
Install-Package MongoDB.Driver
新增實體模型
將 Models 目錄新增至專案根目錄。
使用下列程式代碼將類別
Book
新增至 Models 目錄:using MongoDB.Bson; using MongoDB.Bson.Serialization.Attributes; namespace BookStoreApi.Models; public class Book { [BsonId] [BsonRepresentation(BsonType.ObjectId)] public string? Id { get; set; } [BsonElement("Name")] public string BookName { get; set; } = null!; public decimal Price { get; set; } public string Category { get; set; } = null!; public string Author { get; set; } = null!; }
在上述類別中,
Id
屬性為:- 將 Common Language Runtime (CLR) 物件對應到 MongoDB 集合所需。
- 使用
[BsonId]
標註,以讓此屬性成為文件的主索引鍵。 - 加上
[BsonRepresentation(BsonType.ObjectId)]
批註,以允許將參數傳遞為型別string
,而非ObjectId結構。 Mongo 會處理從string
轉換到ObjectId
的作業。
BookName
屬性會使用[BsonElement]
屬性標註。Name
的屬性值代表 MongoDB 集合中的屬性名稱。
新增組態模型
將下列資料庫設定值新增至
appsettings.json
:{ "BookStoreDatabase": { "ConnectionString": "mongodb://localhost:27017", "DatabaseName": "BookStore", "BooksCollectionName": "Books" }, "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Warning" } }, "AllowedHosts": "*" }
使用下列程式代碼將類別
BookStoreDatabaseSettings
新增至 Models 目錄:namespace BookStoreApi.Models; public class BookStoreDatabaseSettings { public string ConnectionString { get; set; } = null!; public string DatabaseName { get; set; } = null!; public string BooksCollectionName { get; set; } = null!; }
上述
BookStoreDatabaseSettings
類別是用來儲存appsettings.json
檔案的BookStoreDatabase
屬性值。 JSON 和 C# 屬性名稱以相同方式命名,以簡化對應程序。將下列醒目提示的程式碼新增至
Program.cs
:var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.Configure<BookStoreDatabaseSettings>( builder.Configuration.GetSection("BookStoreDatabase"));
在上述程式碼中,
appsettings.json
檔案的BookStoreDatabase
區段所繫結的設定執行個體已註冊在相依性注入 (DI) 容器中。 例如,BookStoreDatabaseSettings
物件的ConnectionString
屬性會填入BookStoreDatabase:ConnectionString
中的appsettings.json
屬性。在
Program.cs
的頂端新增下列程式碼,以解析BookStoreDatabaseSettings
參考:using BookStoreApi.Models;
新增 CRUD 作業服務
將 Services 目錄新增至專案根目錄。
使用下列程式代碼將類別
BooksService
新增至 Services 目錄:using BookStoreApi.Models; using Microsoft.Extensions.Options; using MongoDB.Driver; namespace BookStoreApi.Services; public class BooksService { private readonly IMongoCollection<Book> _booksCollection; public BooksService( IOptions<BookStoreDatabaseSettings> bookStoreDatabaseSettings) { var mongoClient = new MongoClient( bookStoreDatabaseSettings.Value.ConnectionString); var mongoDatabase = mongoClient.GetDatabase( bookStoreDatabaseSettings.Value.DatabaseName); _booksCollection = mongoDatabase.GetCollection<Book>( bookStoreDatabaseSettings.Value.BooksCollectionName); } public async Task<List<Book>> GetAsync() => await _booksCollection.Find(_ => true).ToListAsync(); public async Task<Book?> GetAsync(string id) => await _booksCollection.Find(x => x.Id == id).FirstOrDefaultAsync(); public async Task CreateAsync(Book newBook) => await _booksCollection.InsertOneAsync(newBook); public async Task UpdateAsync(string id, Book updatedBook) => await _booksCollection.ReplaceOneAsync(x => x.Id == id, updatedBook); public async Task RemoveAsync(string id) => await _booksCollection.DeleteOneAsync(x => x.Id == id); }
在前面的程式碼中,一個
BookStoreDatabaseSettings
執行個體是透過建構子注入從 DI 取得的。 此技術可讓您存取在appsettings.json
一節中新增的設定值。將下列醒目提示的程式碼新增至
Program.cs
:var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.Configure<BookStoreDatabaseSettings>( builder.Configuration.GetSection("BookStoreDatabase")); builder.Services.AddSingleton<BooksService>();
在上述程式碼中,
BooksService
類別要向 DI 註冊才能在取用類別中支援建構函式插入。 因為BooksService
直接依存於MongoClient
,所以 Singleton 服務存留期最適合。 根據官方的 Mongo 用戶端重複使用指導方針,應該將MongoClient
註冊為 DI 中的單例服務存留期。在
Program.cs
的頂端新增下列程式碼,以解析BooksService
參考:using BookStoreApi.Services;
BooksService
類別使用下列 MongoDB.Driver
成員來對資料庫執行 CRUD 作業:
MongoClient:讀取執行資料庫作業的伺服器實例。 此類別的建構函式會被賦予一個 MongoDB 連接字串:
public BooksService( IOptions<BookStoreDatabaseSettings> bookStoreDatabaseSettings) { var mongoClient = new MongoClient( bookStoreDatabaseSettings.Value.ConnectionString); var mongoDatabase = mongoClient.GetDatabase( bookStoreDatabaseSettings.Value.DatabaseName); _booksCollection = mongoDatabase.GetCollection<Book>( bookStoreDatabaseSettings.Value.BooksCollectionName); }
IMongoDatabase:代表執行作業的 Mongo 資料庫。 本教學課程使用 介面上的一般 GetCollection<TDocument>(collection) 方法,以存取特定集合中的數據。 呼叫此方法之後,針對集合執行 CRUD 作業。 在
GetCollection<TDocument>(collection)
方法呼叫中:-
collection
代表集合名稱。 -
TDocument
代表儲存在集合中的 CLR 物件類型。
-
GetCollection<TDocument>(collection)
會傳回代表集合的 MongoCollection 物件。 在此教程中,會在集合上調用下列方法:
- DeleteOneAsync:刪除符合所提供搜尋準則的單一檔。
- 找到<TDocument>:傳回集合中符合所提供搜尋準則的所有檔。
- InsertOneAsync:將提供的 物件插入為集合中的新檔。
- ReplaceOneAsync:將符合所提供搜尋準則的單一檔取代為提供的物件。
新增控制器
使用下列程式代碼將類別 BooksController
新增至 Controllers 目錄:
using BookStoreApi.Models;
using BookStoreApi.Services;
using Microsoft.AspNetCore.Mvc;
namespace BookStoreApi.Controllers;
[ApiController]
[Route("api/[controller]")]
public class BooksController : ControllerBase
{
private readonly BooksService _booksService;
public BooksController(BooksService booksService) =>
_booksService = booksService;
[HttpGet]
public async Task<List<Book>> Get() =>
await _booksService.GetAsync();
[HttpGet("{id:length(24)}")]
public async Task<ActionResult<Book>> Get(string id)
{
var book = await _booksService.GetAsync(id);
if (book is null)
{
return NotFound();
}
return book;
}
[HttpPost]
public async Task<IActionResult> Post(Book newBook)
{
await _booksService.CreateAsync(newBook);
return CreatedAtAction(nameof(Get), new { id = newBook.Id }, newBook);
}
[HttpPut("{id:length(24)}")]
public async Task<IActionResult> Update(string id, Book updatedBook)
{
var book = await _booksService.GetAsync(id);
if (book is null)
{
return NotFound();
}
updatedBook.Id = book.Id;
await _booksService.UpdateAsync(id, updatedBook);
return NoContent();
}
[HttpDelete("{id:length(24)}")]
public async Task<IActionResult> Delete(string id)
{
var book = await _booksService.GetAsync(id);
if (book is null)
{
return NotFound();
}
await _booksService.RemoveAsync(id);
return NoContent();
}
}
之前的 Web API 控制器。
- 使用
BooksService
類別來執行 CRUD 作業。 - 包含動作方法以支援 GET、POST、PUT 與 DELETE HTTP 要求。
- 在CreatedAtAction 動作方法中呼叫
Create
,以傳回 HTTP 201 回應。 對於可在伺服器上建立新資源的 HTTP POST 方法,其標準回應是狀態碼 201。CreatedAtAction
也會將Location
標頭新增至回應。Location
標頭指定新建書籍的 URI。
測試 Web API
建置並執行應用程式。
瀏覽至
https://localhost:<port>/api/books
,其中的<port>
是應用程式自動指派的連接埠號碼,以測試控制器的無參數Get
動作方法。 類似下列的 JSON 回應隨即會顯示:[ { "id": "61a6058e6c43f32854e51f51", "bookName": "Design Patterns", "price": 54.93, "category": "Computers", "author": "Ralph Johnson" }, { "id": "61a6058e6c43f32854e51f52", "bookName": "Clean Code", "price": 43.15, "category": "Computers", "author": "Robert C. Martin" } ]
巡覽至
https://localhost:<port>/api/books/{id here}
,測試控制器的多載Get
動作方法。 類似下列的 JSON 回應隨即會顯示:{ "id": "61a6058e6c43f32854e51f52", "bookName": "Clean Code", "price": 43.15, "category": "Computers", "author": "Robert C. Martin" }
設定 JSON 序列化選項
有兩個細節需要變更,此變更涉及在「測試 Web API」章節中傳回的 JSON 回應。
- 屬性名稱的預設駝峰式大小寫應更改,使其符合 CLR 物件屬性的 Pascal 大小寫。
-
bookName
屬性應傳回為Name
。
為滿足上述需求,請進行下列變更:
在
Program.cs
中,將下列醒目提示的程式碼鏈結至AddControllers
方法呼叫:var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.Configure<BookStoreDatabaseSettings>( builder.Configuration.GetSection("BookStoreDatabase")); builder.Services.AddSingleton<BooksService>(); builder.Services.AddControllers() .AddJsonOptions( options => options.JsonSerializerOptions.PropertyNamingPolicy = null);
完成前述變更後,Web API 序列化 JSON 回應中屬性名稱即符合其對應的 CLR 物件類型屬性名稱。 例如,
Book
類別的Author
屬性會序列化為Author
,而非author
。在
Models/Book.cs
中,為BookName
屬性標註[JsonPropertyName]
屬性:[BsonElement("Name")] [JsonPropertyName("Name")] public string BookName { get; set; } = null!;
[JsonPropertyName]
的屬性值Name
代表 Web API 序列化 JSON 回應中的屬性名稱。在
Models/Book.cs
的頂端新增下列程式碼,以解析[JsonProperty]
屬性參考:using System.Text.Json.Serialization;
重複測試 Web API 一節中定義的步驟。 請注意 JSON 屬性名稱中的差異。
將驗證支援新增至 Web API
ASP.NET Core Identity 會將使用者介面 (UI) 登入功能新增至 ASP.NET Core Web 應用程式。 若要保護 Web API 和 SPA,請使用下列其中一項:
- Microsoft Entra 身份識別
- Azure Active Directory B2C (Azure AD B2C)
- Duende Identity 伺服器
Duende Identity 伺服器是適用於 ASP.NET Core 的 OpenID Connect 和 OAuth 2.0 架構。 Duende Identity 伺服器會啟用下列安全性功能:
- 驗證即服務 (AaaS)
- 多個應用程式類型的單一登入/登出 (SSO)
- API 的存取控制
- 同盟閘道
重要
Duende Software 可能會要求您支付使用 Duende Identity 伺服器的授權費用。 如需詳細資訊,請參閱 從 .NET 5 中的 ASP.NET Core 移轉至 .NET 6。
如需詳細資訊,請參閱 Duende 伺服器檔(Duende Identity Software 網站)。
其他資源
本教學課程會建立 Web API,以在 MongoDB NoSQL 資料庫上執行建立、讀取、更新和刪除 (CRUD) 作業。
在本教學課程中,您會了解如何:
- 設定 MongoDB
- 建立 MongoDB 資料庫
- 定義 MongoDB 集合與結構描述
- 從 Web API 執行 MongoDB CRUD 作業
- 自訂 JSON 序列化
必要條件
- .NET Core SDK 3.0 或更新版本
- 具有 ASP.NET 和 Web 開發工作負載的 Visual Studio 2019
- MongoDB 資料庫
設定 MongoDB
如果使用 Windows,則 MongoDB 預設會安裝在 C:\Program Files\MongoDB 。 將 C:\Program Files\MongoDB\Server\<version_number>\bin 新增至 Path
環境變數。 此變更會啟用從您開發機器上的任意位置存取 MongoDB 的功能。
在下列步驟中使用 mongo 殼層來建立資料庫、建立集合及存放文件。 如需 mongo Shell 命令的詳細資訊,請參閱 使用 mongo Shell。
選擇您開發機器上的目錄來存放資料。 例如, Windows 上的 C:\BooksData 。 若該目錄不存在,請建立它。 mongo Shell 不會建立新目錄。
開啟命令提示字元。 執行下列命令以連線到預設連接埠 27017 上的 MongoDB。 請記得將
<data_directory_path>
替換為您在上一個步驟中選擇的目錄。mongod --dbpath <data_directory_path>
開啟另一個命令提示字元實例。 執行下列命令以連線到預設測試資料庫:
mongo
在命令提示字元中執行下列命令:
use BookstoreDb
如果 BookstoreDb 不存在,就會建立名為 BookstoreDb 的資料庫。 若該資料庫存在,會開啟其連線進行交易。
使用下列命令建立
Books
集合:db.createCollection('Books')
顯示的結果如下:
{ "ok" : 1 }
使用下列命令為
Books
集合定義結構描述並插入兩份文件:db.Books.insertMany([{'Name':'Design Patterns','Price':54.93,'Category':'Computers','Author':'Ralph Johnson'}, {'Name':'Clean Code','Price':43.15,'Category':'Computers','Author':'Robert C. Martin'}])
顯示的結果如下:
{ "acknowledged" : true, "insertedIds" : [ ObjectId("5bfd996f7b8e48dc15ff215d"), ObjectId("5bfd996f7b8e48dc15ff215e") ] }
注意
您執行此範例時的識別碼,將不同於本文中顯示的識別碼。
使用下列命令檢視資料庫中的文件:
db.Books.find({}).pretty()
顯示的結果如下:
{ "_id" : ObjectId("5bfd996f7b8e48dc15ff215d"), "Name" : "Design Patterns", "Price" : 54.93, "Category" : "Computers", "Author" : "Ralph Johnson" } { "_id" : ObjectId("5bfd996f7b8e48dc15ff215e"), "Name" : "Clean Code", "Price" : 43.15, "Category" : "Computers", "Author" : "Robert C. Martin" }
結構描述會為每份文件新增自動生成的
_id
屬性 (類型ObjectId
)。
資料庫已就緒。 您可以開始建立 ASP.NET Core Web API。
建立 ASP.NET Core Web API 專案
移至 [ 檔案>新>專案]。
選取 [ASP.NET Core Web 應用程式] 專案類型,然後選取 [下一步]。
將專案命名為 BooksApi,然後選取 [建立]。
選取 [.NET Core] 目標架構與 [ASP.NET Core 3.0]。 選取 [API] 專案範本,然後選取 [確定]。
請流覽 NuGet 資源庫:MongoDB.Driver ,以判斷適用於 MongoDB 的 .NET 驅動程式最新穩定版本。 在 [套件管理員主控台] 視窗中,瀏覽到專案根目錄。 執行下列命令以安裝適用於 MongoDB 的 .NET 驅動程式:
Install-Package MongoDB.Driver -Version {VERSION}
新增實體模型
將 Models 目錄新增至專案根目錄。
使用下列程式代碼將類別
Book
新增至 Models 目錄:using MongoDB.Bson; using MongoDB.Bson.Serialization.Attributes; namespace BooksApi.Models { public class Book { [BsonId] [BsonRepresentation(BsonType.ObjectId)] public string Id { get; set; } [BsonElement("Name")] public string BookName { get; set; } public decimal Price { get; set; } public string Category { get; set; } public string Author { get; set; } } }
在上述類別中,
Id
屬性為:- 將 Common Language Runtime (CLR) 物件對應到 MongoDB 集合所需。
- 使用
[BsonId]
標註,以讓此屬性成為文件的主索引鍵。 - 加上
[BsonRepresentation(BsonType.ObjectId)]
批註,以允許將參數傳遞為型別string
,而非ObjectId結構。 Mongo 會處理從string
轉換到ObjectId
的作業。
BookName
屬性會使用[BsonElement]
屬性標註。Name
的屬性值代表 MongoDB 集合中的屬性名稱。
新增組態模型
將下列資料庫設定值新增至
appsettings.json
:{ "BookstoreDatabaseSettings": { "BooksCollectionName": "Books", "ConnectionString": "mongodb://localhost:27017", "DatabaseName": "BookstoreDb" }, "Logging": { "IncludeScopes": false, "Debug": { "LogLevel": { "Default": "Warning" } }, "Console": { "LogLevel": { "Default": "Warning" } } } }
BookstoreDatabaseSettings.cs
使用下列程式代碼將檔案新增至 Models 目錄:namespace BooksApi.Models { public class BookstoreDatabaseSettings : IBookstoreDatabaseSettings { public string BooksCollectionName { get; set; } public string ConnectionString { get; set; } public string DatabaseName { get; set; } } public interface IBookstoreDatabaseSettings { string BooksCollectionName { get; set; } string ConnectionString { get; set; } string DatabaseName { get; set; } } }
上述
BookstoreDatabaseSettings
類別是用來儲存appsettings.json
檔案的BookstoreDatabaseSettings
屬性值。 JSON 和 C# 屬性名稱以相同方式命名,以簡化對應程序。將下列醒目提示的程式碼新增至
Startup.ConfigureServices
:public void ConfigureServices(IServiceCollection services) { // requires using Microsoft.Extensions.Options services.Configure<BookstoreDatabaseSettings>( Configuration.GetSection(nameof(BookstoreDatabaseSettings))); services.AddSingleton<IBookstoreDatabaseSettings>(sp => sp.GetRequiredService<IOptions<BookstoreDatabaseSettings>>().Value); services.AddControllers(); }
在上述程式碼中:
-
appsettings.json
檔案的BookstoreDatabaseSettings
區段所綁定的配置實例已在依賴注入 (DI) 容器中註冊。 例如,BookstoreDatabaseSettings
物件的ConnectionString
屬性會填入BookstoreDatabaseSettings:ConnectionString
中的appsettings.json
屬性。 - 介面
IBookstoreDatabaseSettings
會以單態服務生命週期在 DI 中註冊。 插入時,介面執行個體會解析成BookstoreDatabaseSettings
物件。
-
在
Startup.cs
的頂端新增下列程式碼,以解析BookstoreDatabaseSettings
和IBookstoreDatabaseSettings
參考:using BooksApi.Models;
新增 CRUD 作業服務
將 Services 目錄新增至專案根目錄。
使用下列程式代碼將類別
BookService
新增至 Services 目錄:using BooksApi.Models; using MongoDB.Driver; using System.Collections.Generic; using System.Linq; namespace BooksApi.Services { public class BookService { private readonly IMongoCollection<Book> _books; public BookService(IBookstoreDatabaseSettings settings) { var client = new MongoClient(settings.ConnectionString); var database = client.GetDatabase(settings.DatabaseName); _books = database.GetCollection<Book>(settings.BooksCollectionName); } public List<Book> Get() => _books.Find(book => true).ToList(); public Book Get(string id) => _books.Find<Book>(book => book.Id == id).FirstOrDefault(); public Book Create(Book book) { _books.InsertOne(book); return book; } public void Update(string id, Book bookIn) => _books.ReplaceOne(book => book.Id == id, bookIn); public void Remove(Book bookIn) => _books.DeleteOne(book => book.Id == bookIn.Id); public void Remove(string id) => _books.DeleteOne(book => book.Id == id); } }
在上述程式碼中,透過建構子插入從 DI 獲取
IBookstoreDatabaseSettings
的實例。 此技術可讓您存取在appsettings.json
一節中新增的設定值。將下列醒目提示的程式碼新增至
Startup.ConfigureServices
:public void ConfigureServices(IServiceCollection services) { services.Configure<BookstoreDatabaseSettings>( Configuration.GetSection(nameof(BookstoreDatabaseSettings))); services.AddSingleton<IBookstoreDatabaseSettings>(sp => sp.GetRequiredService<IOptions<BookstoreDatabaseSettings>>().Value); services.AddSingleton<BookService>(); services.AddControllers(); }
在上述程式碼中,
BookService
類別要向 DI 註冊才能在取用類別中支援建構函式插入。 因為BookService
直接依存於MongoClient
,所以 Singleton 服務存留期最適合。 根據官方的 Mongo 用戶端重複使用指導方針,應該將MongoClient
註冊為 DI 中的單例服務存留期。在
Startup.cs
的頂端新增下列程式碼,以解析BookService
參考:using BooksApi.Services;
BookService
類別使用下列 MongoDB.Driver
成員來對資料庫執行 CRUD 作業:
MongoClient:讀取執行資料庫作業的伺服器實例。 此類別的建構函式會被賦予一個 MongoDB 連接字串:
public BookService(IBookstoreDatabaseSettings settings) { var client = new MongoClient(settings.ConnectionString); var database = client.GetDatabase(settings.DatabaseName); _books = database.GetCollection<Book>(settings.BooksCollectionName); }
IMongoDatabase:代表執行作業的 Mongo 資料庫。 本教學課程使用 介面上的一般 GetCollection<TDocument>(collection) 方法,以存取特定集合中的數據。 呼叫此方法之後,針對集合執行 CRUD 作業。 在
GetCollection<TDocument>(collection)
方法呼叫中:-
collection
代表集合名稱。 -
TDocument
代表儲存在集合中的 CLR 物件類型。
-
GetCollection<TDocument>(collection)
會傳回代表集合的 MongoCollection 物件。 在此教程中,會在集合上調用下列方法:
- DeleteOne:刪除符合所提供搜尋準則的單一檔。
- 找到<TDocument>:傳回集合中符合所提供搜尋準則的所有檔。
- InsertOne:將提供的 物件插入為集合中的新檔。
- ReplaceOne:將符合所提供搜尋準則的單一檔取代為提供的 物件。
新增控制器
使用下列程式代碼將類別 BooksController
新增至 Controllers 目錄:
using BooksApi.Models;
using BooksApi.Services;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
namespace BooksApi.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class BooksController : ControllerBase
{
private readonly BookService _bookService;
public BooksController(BookService bookService)
{
_bookService = bookService;
}
[HttpGet]
public ActionResult<List<Book>> Get() =>
_bookService.Get();
[HttpGet("{id:length(24)}", Name = "GetBook")]
public ActionResult<Book> Get(string id)
{
var book = _bookService.Get(id);
if (book == null)
{
return NotFound();
}
return book;
}
[HttpPost]
public ActionResult<Book> Create(Book book)
{
_bookService.Create(book);
return CreatedAtRoute("GetBook", new { id = book.Id.ToString() }, book);
}
[HttpPut("{id:length(24)}")]
public IActionResult Update(string id, Book bookIn)
{
var book = _bookService.Get(id);
if (book == null)
{
return NotFound();
}
_bookService.Update(id, bookIn);
return NoContent();
}
[HttpDelete("{id:length(24)}")]
public IActionResult Delete(string id)
{
var book = _bookService.Get(id);
if (book == null)
{
return NotFound();
}
_bookService.Remove(id);
return NoContent();
}
}
}
之前的 Web API 控制器。
- 使用
BookService
類別來執行 CRUD 作業。 - 包含動作方法以支援 GET、POST、PUT 與 DELETE HTTP 要求。
- 在CreatedAtRoute 動作方法中呼叫
Create
,以傳回 HTTP 201 回應。 對於可在伺服器上建立新資源的 HTTP POST 方法,其標準回應是狀態碼 201。CreatedAtRoute
也會將Location
標頭新增至回應。Location
標頭指定新建書籍的 URI。
測試 Web API
建置並執行應用程式。
巡覽至
https://localhost:<port>/api/books
,測試控制器的無參數Get
動作方法。 會顯示下列 JSON 回應:[ { "id":"5bfd996f7b8e48dc15ff215d", "bookName":"Design Patterns", "price":54.93, "category":"Computers", "author":"Ralph Johnson" }, { "id":"5bfd996f7b8e48dc15ff215e", "bookName":"Clean Code", "price":43.15, "category":"Computers", "author":"Robert C. Martin" } ]
巡覽至
https://localhost:<port>/api/books/{id here}
,測試控制器的多載Get
動作方法。 會顯示下列 JSON 回應:{ "id":"{ID}", "bookName":"Clean Code", "price":43.15, "category":"Computers", "author":"Robert C. Martin" }
設定 JSON 序列化選項
有兩個細節需要變更,此變更涉及在「測試 Web API」章節中傳回的 JSON 回應。
- 屬性名稱的預設駝峰式大小寫應更改,使其符合 CLR 物件屬性的 Pascal 大小寫。
-
bookName
屬性應傳回為Name
。
為滿足上述需求,請進行下列變更:
已從 ASP.NET 共用架構移除 Json.NET。 將套件參考新增至
Microsoft.AspNetCore.Mvc.NewtonsoftJson
。在
Startup.ConfigureServices
中,將下列醒目提示的程式碼鏈結至AddControllers
方法呼叫:public void ConfigureServices(IServiceCollection services) { services.Configure<BookstoreDatabaseSettings>( Configuration.GetSection(nameof(BookstoreDatabaseSettings))); services.AddSingleton<IBookstoreDatabaseSettings>(sp => sp.GetRequiredService<IOptions<BookstoreDatabaseSettings>>().Value); services.AddSingleton<BookService>(); services.AddControllers() .AddNewtonsoftJson(options => options.UseMemberCasing()); }
完成前述變更後,Web API 序列化 JSON 回應中屬性名稱即符合其對應的 CLR 物件類型屬性名稱。 例如,
Book
類別的Author
屬性會序列化為Author
。在
Models/Book.cs
中,使用下列BookName
屬性來標註[JsonProperty]
屬性。[BsonElement("Name")] [JsonProperty("Name")] public string BookName { get; set; }
[JsonProperty]
的屬性值Name
代表 Web API 序列化 JSON 回應中的屬性名稱。在
Models/Book.cs
的頂端新增下列程式碼,以解析[JsonProperty]
屬性參考:using Newtonsoft.Json;
重複測試 Web API 一節中定義的步驟。 請注意 JSON 屬性名稱中的差異。
將驗證支援新增至 Web API
ASP.NET Core Identity 會將使用者介面 (UI) 登入功能新增至 ASP.NET Core Web 應用程式。 若要保護 Web API 和 SPA,請使用下列其中一項:
- Microsoft Entra 身份識別
- Azure Active Directory B2C (Azure AD B2C)
- Duende IdentityServer。 Duende IdentityServer 是協力廠商產品。
Duende IdentityServer 是適用於 ASP.NET Core 的 OpenID Connect 和 OAuth 2.0 架構。 Duende IdentityServer 會啟用下列安全性功能:
- 驗證即服務 (AaaS)
- 多個應用程式類型的單一登入/登出 (SSO)
- API 的存取控制
- 同盟閘道
如需詳細資訊,請參閱 Duende IdentityServer 概觀。
如需其他驗證提供者的詳細資訊,請參閱 ASP.NET Core 的社群 OSS 驗證選項
下一步
如需有關建置 ASP.NET Core Web API 的詳細資訊,請參閱下列資源: