使用 ASP.NET Core 與 MongoDB 建立 Web API
注意
這不是這篇文章的最新版本。 如需目前版本,請參閱本文的 .NET 8 版本。
警告
不再支援此版本的 ASP.NET Core。 如需詳細資訊,請參閱 .NET 和 .NET Core 支援原則。 如需目前版本,請參閱本文的 .NET 8 版本。
作者:Pratik Khandelwal 與 Scott Addie
此教學課程會建立 Web API,其會在 MongoDB NoSQL 資料庫上執行建立、讀取、更新及刪除 (CRUD) 作業。
在本教學課程中,您會了解如何:
- 設定 MongoDB
- 建立 MongoDB 資料庫
- 定義 MongoDB 集合與結構描述
- 從 Web API 執行 MongoDB CRUD 作業
- 自訂 JSON 序列化
必要條件
Visual Studio 2022 和 ASP.NET 與 Web 開發工作負載。
設定 MongoDB
從開發機器上的任何位置啟用 MongoDB 和 Mongo DB 殼層存取 (Windows/Linux/macOS):
下載並安裝 MongoDB Shell:
- macOS/Linux: 選擇要擷取 MongoDB Shell 的目錄。 將針對
mongosh
產生的路徑新增至PATH
環境變數。 - Windows: MongoDB 殼層 (mongosh.exe) 安裝在 C:\Users<使用者>\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 的資料庫。 若該資料庫存在,會開啟其連線進行交易。
使用下列命令建立
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
屬性會填入appsettings.json
中的BookStoreDatabase:ConnectionString
屬性。在
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); }
在上述程式碼中,透過建構函式插入從 DI 擷取
BookStoreDatabaseSettings
執行個體。 此技術可讓您存取新增設定模型一節中新增的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 註冊 Singleton 服務存留期。在
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:刪除符合所提供搜尋條件的單一文件。
- Find<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 要求。
- 在
Create
動作方法中呼叫 CreatedAtAction,以傳回 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 ID
- Azure Active Directory B2C (Azure AD B2C)
- Duende Identity 伺服器
Duende Identity 伺服器是適用於 ASP.NET Core 的 OpenID Connect 和 OAuth 2.0 架構。 Duende Identity 伺服器會啟用下列安全性功能:
- 驗證即服務 (AaaS)
- 多個應用程式類型的單一登入/登出 (SSO)
- API 的存取控制
- Federation Gateway
重要
Duende Software 可能會要求您支付授權費用才能在生產環境中使用 Duende Identity 伺服器。 如需詳細資訊,請參閱從 ASP.NET Core 5.0 移轉至 6.0。
如需詳細資訊,請參閱 Duende Identity 伺服器文件 (Duende Software 網站)。
其他資源
此教學課程會建立 Web API,其會在 MongoDB NoSQL 資料庫上執行建立、讀取、更新及刪除 (CRUD) 作業。
在本教學課程中,您會了解如何:
- 設定 MongoDB
- 建立 MongoDB 資料庫
- 定義 MongoDB 集合與結構描述
- 從 Web API 執行 MongoDB CRUD 作業
- 自訂 JSON 序列化
必要條件
Visual Studio 2022 和 ASP.NET 與 Web 開發工作負載。
設定 MongoDB
從開發機器上的任何位置啟用 MongoDB 和 Mongo DB 殼層存取:
在 Windows 上,MongoDB 預設會安裝在 C:\Program Files\MongoDB。 將 C:\Program Files\MongoDB\Server\<version_number>\bin 新增至
PATH
環境變數。下載 MongoDB 殼層,然後選擇要解壓縮的目錄。 將針對
mongosh.exe
產生的路徑新增至PATH
環境變數。選擇開發機器上的目錄來存放資料。 例如, Windows 上的 C:\BooksData。 若該目錄不存在,請建立它。 mongo 殼層不會建立新目錄。
在 OS 命令殼層 (非 MongoDB 殼層) 中,使用下列命令在預設連接埠 27017 上連線到 MongoDB。 將
<data_directory_path>
取代為上一個步驟中所選擇的目錄。mongod --dbpath <data_directory_path>
在下列步驟中使用先前安裝的 MongoDB 殼層來建立資料庫、建立集合及儲存文件。 如需 MongoDB 殼層命令的詳細資訊,請參閱 mongosh
。
啟動
mongosh.exe
來開啟 MongoDB 命令殼層執行個體。執行下列命令,在命令殼層中連線到預設測試資料庫:
mongosh
在命令殼層中執行下列命令:
use 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
屬性會填入appsettings.json
中的BookStoreDatabase:ConnectionString
屬性。在
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); }
在上述程式碼中,透過建構函式插入從 DI 擷取
BookStoreDatabaseSettings
執行個體。 此技術可讓您存取新增設定模型一節中新增的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 註冊 Singleton 服務存留期。在
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:刪除符合所提供搜尋條件的單一文件。
- Find<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 要求。
- 在
Create
動作方法中呼叫 CreatedAtAction,以傳回 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 ID
- Azure Active Directory B2C (Azure AD B2C)
- Duende Identity 伺服器
Duende Identity 伺服器是適用於 ASP.NET Core 的 OpenID Connect 和 OAuth 2.0 架構。 Duende Identity 伺服器會啟用下列安全性功能:
- 驗證即服務 (AaaS)
- 多個應用程式類型的單一登入/登出 (SSO)
- API 的存取控制
- Federation Gateway
重要
Duende Software 可能會要求您支付授權費用才能在生產環境中使用 Duende Identity 伺服器。 如需詳細資訊,請參閱從 ASP.NET Core 5.0 移轉至 6.0。
如需詳細資訊,請參閱 Duende Identity 伺服器文件 (Duende Software 網站)。
其他資源
此教學課程會建立 Web API,其會在 MongoDB NoSQL 資料庫上執行建立、讀取、更新及刪除 (CRUD) 作業。
在本教學課程中,您會了解如何:
- 設定 MongoDB
- 建立 MongoDB 資料庫
- 定義 MongoDB 集合與結構描述
- 從 Web API 執行 MongoDB CRUD 作業
- 自訂 JSON 序列化
必要條件
- Visual Studio 2022 和 ASP.NET 與 Web 開發工作負載。
- .NET 6.0 SDK
設定 MongoDB
從開發機器上的任何位置啟用 MongoDB 和 Mongo DB 殼層存取:
在 Windows 上,MongoDB 預設會安裝在 C:\Program Files\MongoDB。 將 C:\Program Files\MongoDB\Server\<version_number>\bin 新增至
PATH
環境變數。下載 MongoDB 殼層,然後選擇要解壓縮的目錄。 將針對
mongosh.exe
產生的路徑新增至PATH
環境變數。選擇開發機器上的目錄來存放資料。 例如, Windows 上的 C:\BooksData。 若該目錄不存在,請建立它。 mongo 殼層不會建立新目錄。
在 OS 命令殼層 (非 MongoDB 殼層) 中,使用下列命令在預設連接埠 27017 上連線到 MongoDB。 將
<data_directory_path>
取代為上一個步驟中所選擇的目錄。mongod --dbpath <data_directory_path>
在下列步驟中使用先前安裝的 MongoDB 殼層來建立資料庫、建立集合及儲存文件。 如需 MongoDB 殼層命令的詳細資訊,請參閱 mongosh
。
啟動
mongosh.exe
來開啟 MongoDB 命令殼層執行個體。執行下列命令,在命令殼層中連線到預設測試資料庫:
mongosh
在命令殼層中執行下列命令:
use 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
屬性會填入appsettings.json
中的BookStoreDatabase:ConnectionString
屬性。在
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); }
在上述程式碼中,透過建構函式插入從 DI 擷取
BookStoreDatabaseSettings
執行個體。 此技術可讓您存取新增設定模型一節中新增的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 註冊 Singleton 服務存留期。在
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:刪除符合所提供搜尋條件的單一文件。
- Find<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 要求。
- 在
Create
動作方法中呼叫 CreatedAtAction,以傳回 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 ID
- Azure Active Directory B2C (Azure AD B2C)
- Duende Identity 伺服器
Duende Identity 伺服器是適用於 ASP.NET Core 的 OpenID Connect 和 OAuth 2.0 架構。 Duende Identity 伺服器會啟用下列安全性功能:
- 驗證即服務 (AaaS)
- 多個應用程式類型的單一登入/登出 (SSO)
- API 的存取控制
- Federation Gateway
重要
Duende Software 可能會要求您支付授權費用才能在生產環境中使用 Duende Identity 伺服器。 如需詳細資訊,請參閱從 ASP.NET Core 5.0 移轉至 6.0。
如需詳細資訊,請參閱 Duende Identity 伺服器文件 (Duende Software 網站)。
其他資源
此教學課程會建立 Web API,其會在 MongoDB NoSQL 資料庫上執行建立、讀取、更新及刪除 (CRUD) 作業。
在本教學課程中,您會了解如何:
- 設定 MongoDB
- 建立 MongoDB 資料庫
- 定義 MongoDB 集合與結構描述
- 從 Web API 執行 MongoDB CRUD 作業
- 自訂 JSON 序列化
檢視或下載範例程式碼 \(英文\) (如何下載)
必要條件
- .NET Core SDK 3.0 或更新版本
- Visual Studio 2019 和 ASP.NET 與 Web 開發工作負載
- MongoDB
設定 MongoDB
若使用 Windows,MongoDB 預設會安裝在 C:\Program Files\MongoDB。 將 C:\Program Files\MongoDB\Server\<version_number>\bin 新增至 Path
環境變數。 此變更會啟用從您開發機器上的任意位置存取 MongoDB 的功能。
在下列步驟中使用 mongo 殼層來建立資料庫、建立集合及存放文件。 如需有關 mongo 殼層命令的詳細資訊,請參閱使用 mongo 殼層。
選擇您開發機器上的目錄來存放資料。 例如, Windows 上的 C:\BooksData。 若該目錄不存在,請建立它。 mongo 殼層不會建立新目錄。
開啟命令殼層。 執行下列命令以連線到預設連接埠 27017 上的 MongoDB。 請記得將
<data_directory_path>
取代為您在上一個步驟中選擇的目錄。mongod --dbpath <data_directory_path>
開啟另一個命令殼層執行個體。 執行下列命令以連線到預設測試資料庫:
mongo
在命令殼層中執行下列命令:
use 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 Gallery: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
屬性會填入appsettings.json
中的BookstoreDatabaseSettings:ConnectionString
屬性。IBookstoreDatabaseSettings
介面使用 singleton 服務存留期在 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 註冊 Singleton 服務存留期。在
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:刪除符合所提供搜尋條件的單一文件。
- Find<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 要求。
- 在
Create
動作方法中呼叫 CreatedAtRoute,以傳回 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
中,使用下列[JsonProperty]
屬性標註BookName
屬性:[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 ID
- 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 的存取控制
- Federation Gateway
如需詳細資訊,請參閱 Duende IdentityServer 概觀。
如需其他驗證提供者的詳細資訊,請參閱 ASP.NET Core 的社群 OSS 驗證選項
下一步
如需有關建置 ASP.NET Core Web API 的詳細資訊,請參閱下列資源: