使用 ASP.NET Core 與 MongoDB 建立 Web API

注意

這不是這篇文章的最新版本。 如需目前版本,請參閱本文的 .NET 8 版本

重要

這些發行前產品的相關資訊在產品正式發行前可能會有大幅修改。 Microsoft 對此處提供的資訊,不做任何明確或隱含的瑕疵擔保。

如需目前版本,請參閱本文的 .NET 8 版本

作者:Pratik KhandelwalScott Addie

此教學課程會建立 Web API,其會在 MongoDB NoSQL 資料庫上執行建立、讀取、更新及刪除 (CRUD) 作業。

在本教學課程中,您會了解如何:

  • 設定 MongoDB
  • 建立 MongoDB 資料庫
  • 定義 MongoDB 集合與結構描述
  • 從 Web API 執行 MongoDB CRUD 作業
  • 自訂 JSON 序列化

必要條件

設定 MongoDB

從開發機器上的任何位置啟用 MongoDB 和 Mongo DB 殼層存取 (Windows/Linux/macOS):

  1. 下載並安裝 MongoDB Shell:

    • macOS/Linux: 選擇要擷取 MongoDB Shell 的目錄。 將針對 mongosh 產生的路徑新增至 PATH 環境變數。
    • Windows: MongoDB 殼層 (mongosh.exe) 安裝在 C:\Users<使用者>\AppData\Local\Programs\mongosh。 將針對 mongosh.exe 產生的路徑新增至 PATH 環境變數。
  2. 下載並安裝 MongoDB:

    • macOS/Linux:確認已安裝 MongoDB 的目錄,通常是在 /usr/local/mongodb 中。 將針對 mongodb 產生的路徑新增至 PATH 環境變數。
    • Windows: MongoDB 預設會安裝在 C:\Program Files\MongoDB。 將 C:\Program Files\MongoDB\Server\<version_number>\bin 新增至 PATH 環境變數。
  3. 選擇資料記憶體目錄: 選取開發電腦上的目錄來儲存資料。 若該目錄不存在,請建立它。 MongoDB 殼層不會建立新目錄:

    • macOS/Linux: 例如 /usr/local/var/mongodb
    • Windows: 例如 C:\\BooksData
  4. 在 OS 命令殼層 (非 MongoDB 殼層) 中,使用下列命令在預設連接埠 27017 上連線到 MongoDB。 將 <data_directory_path> 取代為上一個步驟中所選擇的目錄。

    mongod --dbpath <data_directory_path>
    

在下列步驟中使用先前安裝的 MongoDB 殼層來建立資料庫、建立集合及儲存文件。 如需 MongoDB 殼層命令的詳細資訊,請參閱 mongosh

  1. 啟動 mongosh.exe 來開啟 MongoDB 命令殼層執行個體。

  2. 執行下列命令,在命令殼層中連線到預設測試資料庫:

    mongosh
    
  3. 在命令殼層中執行下列命令:

    use BookStore
    

    如果尚不存在,就會建立名為 BookStore 的資料庫。 若該資料庫存在,會開啟其連線進行交易。

  4. 使用下列命令建立 Books 集合:

    db.createCollection('Books')
    

    顯示的結果如下:

    { "ok" : 1 }
    
  5. 使用下列命令為 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,不符合命令殼層中顯示的結果。

  6. 使用下列命令檢視資料庫中的文件:

    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 專案

  1. 移至 [檔案]>[新增]>[專案]

  2. 選取 [ASP.NET Core Web API] 專案型別,然後選取 [下一步]

  3. 將專案命名為 BookStoreApi,然後選取 [下一步]

  4. 選取 [.NET 8.0 (長期支援)] 架構,然後選取 [建立]

  5. 在 [套件管理員主控台] 視窗中,瀏覽到專案根目錄。 執行下列命令以安裝適用於 MongoDB 的 .NET 驅動程式:

    Install-Package MongoDB.Driver
    

新增實體模型

  1. 新增 Models 目錄到專案根目錄。

  2. 新增具有下列程式碼的 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 集合中的屬性名稱。

新增組態模型

  1. 將下列資料庫設定值新增至 appsettings.json

    {
        "BookStoreDatabase": {
            "ConnectionString": "mongodb://localhost:27017",
            "DatabaseName": "BookStore",
            "BooksCollectionName": "Books"
        },
        "Logging": {
            "LogLevel": {
                "Default": "Information",
                "Microsoft.AspNetCore": "Warning"
            }
        },
        "AllowedHosts": "*"
    }
    
  2. 新增具有下列程式碼的 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# 屬性名稱以相同方式命名,以簡化對應程序。

  3. 將下列醒目提示的程式碼新增至 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 屬性。

  4. Program.cs 的頂端新增下列程式碼,以解析 BookStoreDatabaseSettings 參考:

    using BookStoreApi.Models;
    

新增 CRUD 作業服務

  1. 新增 Services 目錄到專案根目錄。

  2. 新增具有下列程式碼的 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 設定值。

  3. 將下列醒目提示的程式碼新增至 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 服務存留期。

  4. 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

  1. 建置並執行應用程式。

  2. 瀏覽至 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"
      }
    ]
    
  3. 巡覽至 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

為滿足上述需求,請進行下列變更:

  1. 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

  2. Models/Book.cs 中,使用 BookName 屬性標註 [JsonPropertyName] 屬性:

    [BsonElement("Name")]
    [JsonPropertyName("Name")]
    public string BookName { get; set; } = null!;
    

    [JsonPropertyName] 屬性值 Name 代表 Web API 序列化 JSON 回應中的屬性名稱。

  3. Models/Book.cs 的頂端新增下列程式碼,以解析 [JsonProperty] 屬性參考:

    using System.Text.Json.Serialization;
    
  4. 重複測試 Web API 一節中定義的步驟。 請注意 JSON 屬性名稱中的差異。

將驗證支援新增至 Web API

ASP.NET Core Identity 會將使用者介面 (UI) 登入功能新增至 ASP.NET Core Web 應用程式。 若要保護 Web API 和 SPA,請使用下列其中一項:

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 序列化

必要條件

設定 MongoDB

從開發機器上的任何位置啟用 MongoDB 和 Mongo DB 殼層存取:

  1. 在 Windows 上,MongoDB 預設會安裝在 C:\Program Files\MongoDB。 將 C:\Program Files\MongoDB\Server\<version_number>\bin 新增至 PATH 環境變數。

  2. 下載 MongoDB 殼層,然後選擇要解壓縮的目錄。 將針對 mongosh.exe 產生的路徑新增至 PATH 環境變數。

  3. 選擇開發機器上的目錄來存放資料。 例如, Windows 上的 C:\BooksData。 若該目錄不存在,請建立它。 mongo 殼層不會建立新目錄。

  4. 在 OS 命令殼層 (非 MongoDB 殼層) 中,使用下列命令在預設連接埠 27017 上連線到 MongoDB。 將 <data_directory_path> 取代為上一個步驟中所選擇的目錄。

    mongod --dbpath <data_directory_path>
    

在下列步驟中使用先前安裝的 MongoDB 殼層來建立資料庫、建立集合及儲存文件。 如需 MongoDB 殼層命令的詳細資訊,請參閱 mongosh

  1. 啟動 mongosh.exe 來開啟 MongoDB 命令殼層執行個體。

  2. 執行下列命令,在命令殼層中連線到預設測試資料庫:

    mongosh
    
  3. 在命令殼層中執行下列命令:

    use BookStore
    

    如果尚不存在,就會建立名為 BookStore 的資料庫。 若該資料庫存在,會開啟其連線進行交易。

  4. 使用下列命令建立 Books 集合:

    db.createCollection('Books')
    

    顯示的結果如下:

    { "ok" : 1 }
    
  5. 使用下列命令為 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,不符合命令殼層中顯示的結果。

  6. 使用下列命令檢視資料庫中的文件:

    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 專案

  1. 移至 [檔案]>[新增]>[專案]

  2. 選取 [ASP.NET Core Web API] 專案型別,然後選取 [下一步]

  3. 將專案命名為 BookStoreApi,然後選取 [下一步]

  4. 選取 [.NET 7.0 (標準期間支援)] 架構,然後選取 [建立]

  5. 從 [工具] 功能表中,選取 [NuGet 套件管理員]> [套件管理員主控台]

  6. 在 [套件管理員主控台] 視窗中,瀏覽到專案根目錄。 執行下列命令以安裝適用於 MongoDB 的 .NET 驅動程式:

    Install-Package MongoDB.Driver
    

新增實體模型

  1. 新增 Models 目錄到專案根目錄。

  2. 新增具有下列程式碼的 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 集合中的屬性名稱。

新增組態模型

  1. 將下列資料庫設定值新增至 appsettings.json

    {
      "BookStoreDatabase": {
        "ConnectionString": "mongodb://localhost:27017",
        "DatabaseName": "BookStore",
        "BooksCollectionName": "Books"
      },
      "Logging": {
        "LogLevel": {
          "Default": "Information",
          "Microsoft.AspNetCore": "Warning"
        }
      },
      "AllowedHosts": "*"
    }
    
  2. 新增具有下列程式碼的 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# 屬性名稱以相同方式命名,以簡化對應程序。

  3. 將下列醒目提示的程式碼新增至 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 屬性。

  4. Program.cs 的頂端新增下列程式碼,以解析 BookStoreDatabaseSettings 參考:

    using BookStoreApi.Models;
    

新增 CRUD 作業服務

  1. 新增 Services 目錄到專案根目錄。

  2. 新增具有下列程式碼的 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 設定值。

  3. 將下列醒目提示的程式碼新增至 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 服務存留期。

  4. 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

  1. 建置並執行應用程式。

  2. 瀏覽至 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"
      }
    ]
    
  3. 巡覽至 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

為滿足上述需求,請進行下列變更:

  1. 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

  2. Models/Book.cs 中,使用 BookName 屬性標註 [JsonPropertyName] 屬性:

    [BsonElement("Name")]
    [JsonPropertyName("Name")]
    public string BookName { get; set; } = null!;
    

    [JsonPropertyName] 屬性值 Name 代表 Web API 序列化 JSON 回應中的屬性名稱。

  3. Models/Book.cs 的頂端新增下列程式碼,以解析 [JsonProperty] 屬性參考:

    using System.Text.Json.Serialization;
    
  4. 重複測試 Web API 一節中定義的步驟。 請注意 JSON 屬性名稱中的差異。

將驗證支援新增至 Web API

ASP.NET Core Identity 會將使用者介面 (UI) 登入功能新增至 ASP.NET Core Web 應用程式。 若要保護 Web API 和 SPA,請使用下列其中一項:

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 序列化

必要條件

設定 MongoDB

從開發機器上的任何位置啟用 MongoDB 和 Mongo DB 殼層存取:

  1. 在 Windows 上,MongoDB 預設會安裝在 C:\Program Files\MongoDB。 將 C:\Program Files\MongoDB\Server\<version_number>\bin 新增至 PATH 環境變數。

  2. 下載 MongoDB 殼層,然後選擇要解壓縮的目錄。 將針對 mongosh.exe 產生的路徑新增至 PATH 環境變數。

  3. 選擇開發機器上的目錄來存放資料。 例如, Windows 上的 C:\BooksData。 若該目錄不存在,請建立它。 mongo 殼層不會建立新目錄。

  4. 在 OS 命令殼層 (非 MongoDB 殼層) 中,使用下列命令在預設連接埠 27017 上連線到 MongoDB。 將 <data_directory_path> 取代為上一個步驟中所選擇的目錄。

    mongod --dbpath <data_directory_path>
    

在下列步驟中使用先前安裝的 MongoDB 殼層來建立資料庫、建立集合及儲存文件。 如需 MongoDB 殼層命令的詳細資訊,請參閱 mongosh

  1. 啟動 mongosh.exe 來開啟 MongoDB 命令殼層執行個體。

  2. 執行下列命令,在命令殼層中連線到預設測試資料庫:

    mongosh
    
  3. 在命令殼層中執行下列命令:

    use BookStore
    

    如果尚不存在,就會建立名為 BookStore 的資料庫。 若該資料庫存在,會開啟其連線進行交易。

  4. 使用下列命令建立 Books 集合:

    db.createCollection('Books')
    

    顯示的結果如下:

    { "ok" : 1 }
    
  5. 使用下列命令為 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,不符合命令殼層中顯示的結果。

  6. 使用下列命令檢視資料庫中的文件:

    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 專案

  1. 移至 [檔案]>[新增]>[專案]

  2. 選取 [ASP.NET Core Web API] 專案型別,然後選取 [下一步]

  3. 將專案命名為 BookStoreApi,然後選取 [下一步]

  4. 選取 [.NET 6.0 (長期支援)] 架構,然後選取 [建立]

  5. 在 [套件管理員主控台] 視窗中,瀏覽到專案根目錄。 執行下列命令以安裝適用於 MongoDB 的 .NET 驅動程式:

    Install-Package MongoDB.Driver
    

新增實體模型

  1. 新增 Models 目錄到專案根目錄。

  2. 新增具有下列程式碼的 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 集合中的屬性名稱。

新增組態模型

  1. 將下列資料庫設定值新增至 appsettings.json

    {
        "BookStoreDatabase": {
            "ConnectionString": "mongodb://localhost:27017",
            "DatabaseName": "BookStore",
            "BooksCollectionName": "Books"
        },
        "Logging": {
            "LogLevel": {
                "Default": "Information",
                "Microsoft.AspNetCore": "Warning"
            }
        },
        "AllowedHosts": "*"
    }
    
  2. 新增具有下列程式碼的 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# 屬性名稱以相同方式命名,以簡化對應程序。

  3. 將下列醒目提示的程式碼新增至 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 屬性。

  4. Program.cs 的頂端新增下列程式碼,以解析 BookStoreDatabaseSettings 參考:

    using BookStoreApi.Models;
    

新增 CRUD 作業服務

  1. 新增 Services 目錄到專案根目錄。

  2. 新增具有下列程式碼的 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 設定值。

  3. 將下列醒目提示的程式碼新增至 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 服務存留期。

  4. 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

  1. 建置並執行應用程式。

  2. 瀏覽至 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"
      }
    ]
    
  3. 巡覽至 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

為滿足上述需求,請進行下列變更:

  1. 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

  2. Models/Book.cs 中,使用 BookName 屬性標註 [JsonPropertyName] 屬性:

    [BsonElement("Name")]
    [JsonPropertyName("Name")]
    public string BookName { get; set; } = null!;
    

    [JsonPropertyName] 屬性值 Name 代表 Web API 序列化 JSON 回應中的屬性名稱。

  3. Models/Book.cs 的頂端新增下列程式碼,以解析 [JsonProperty] 屬性參考:

    using System.Text.Json.Serialization;
    
  4. 重複測試 Web API 一節中定義的步驟。 請注意 JSON 屬性名稱中的差異。

將驗證支援新增至 Web API

ASP.NET Core Identity 會將使用者介面 (UI) 登入功能新增至 ASP.NET Core Web 應用程式。 若要保護 Web API 和 SPA,請使用下列其中一項:

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 序列化

檢視或下載範例程式碼 \(英文\) (如何下載)

必要條件

設定 MongoDB

若使用 Windows,MongoDB 預設會安裝在 C:\Program Files\MongoDB。 將 C:\Program Files\MongoDB\Server\<version_number>\bin 新增至 Path 環境變數。 此變更會啟用從您開發機器上的任意位置存取 MongoDB 的功能。

在下列步驟中使用 mongo 殼層來建立資料庫、建立集合及存放文件。 如需有關 mongo 殼層命令的詳細資訊,請參閱使用 mongo 殼層

  1. 選擇您開發機器上的目錄來存放資料。 例如, Windows 上的 C:\BooksData。 若該目錄不存在,請建立它。 mongo 殼層不會建立新目錄。

  2. 開啟命令殼層。 執行下列命令以連線到預設連接埠 27017 上的 MongoDB。 請記得將 <data_directory_path> 取代為您在上一個步驟中選擇的目錄。

    mongod --dbpath <data_directory_path>
    
  3. 開啟另一個命令殼層執行個體。 執行下列命令以連線到預設測試資料庫:

    mongo
    
  4. 在命令殼層中執行下列命令:

    use BookstoreDb
    

    如果尚不存在,就會建立名為 BookstoreDb 的資料庫。 若該資料庫存在,會開啟其連線進行交易。

  5. 使用下列命令建立 Books 集合:

    db.createCollection('Books')
    

    顯示的結果如下:

    { "ok" : 1 }
    
  6. 使用下列命令為 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")
      ]
    }
    

    注意

    您執行此範例時的識別碼,將不同於本文中顯示的識別碼。

  7. 使用下列命令檢視資料庫中的文件:

    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 專案

  1. 移至 [檔案]>[新增]>[專案]

  2. 選取 [ASP.NET Core Web 應用程式] 專案類型,然後選取 [下一步]

  3. 將專案命名為 BooksApi,然後選取 [建立]

  4. 選取 [.NET Core] 目標架構與 [ASP.NET Core 3.0]。 選取 [API] 專案範本,然後選取 [確定]

  5. 造訪 NuGet Gallery:MongoDB.Driver 來判斷適用於 MongoDB 的 .NET 驅動程式最新穩定的版本。 在 [套件管理員主控台] 視窗中,瀏覽到專案根目錄。 執行下列命令以安裝適用於 MongoDB 的 .NET 驅動程式:

    Install-Package MongoDB.Driver -Version {VERSION}
    

新增實體模型

  1. 新增 Models 目錄到專案根目錄。

  2. 新增具有下列程式碼的 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 集合中的屬性名稱。

新增組態模型

  1. 將下列資料庫設定值新增至 appsettings.json

    {
      "BookstoreDatabaseSettings": {
        "BooksCollectionName": "Books",
        "ConnectionString": "mongodb://localhost:27017",
        "DatabaseName": "BookstoreDb"
      },
      "Logging": {
        "IncludeScopes": false,
        "Debug": {
          "LogLevel": {
            "Default": "Warning"
          }
        },
        "Console": {
          "LogLevel": {
            "Default": "Warning"
          }
        }
      }
    }
    
  2. 使用下列程式碼將 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# 屬性名稱以相同方式命名,以簡化對應程序。

  3. 將下列醒目提示的程式碼新增至 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 物件。
  4. Startup.cs 的頂端新增下列程式碼,以解析 BookstoreDatabaseSettingsIBookstoreDatabaseSettings 參考:

    using BooksApi.Models;
    

新增 CRUD 作業服務

  1. 新增 Services 目錄到專案根目錄。

  2. 新增具有下列程式碼的 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 設定值。

  3. 將下列醒目提示的程式碼新增至 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 服務存留期。

  4. 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

  1. 建置並執行應用程式。

  2. 巡覽至 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"
      }
    ]
    
  3. 巡覽至 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

為滿足上述需求,請進行下列變更:

  1. 已從 ASP.NET 共用架構移除 Json.NET。 將套件參考新增至 Microsoft.AspNetCore.Mvc.NewtonsoftJson

  2. 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

  3. Models/Book.cs 中,使用下列 [JsonProperty] 屬性標註 BookName 屬性:

    [BsonElement("Name")]
    [JsonProperty("Name")]
    public string BookName { get; set; }
    

    [JsonProperty] 屬性值 Name 代表 Web API 序列化 JSON 回應中的屬性名稱。

  4. Models/Book.cs 的頂端新增下列程式碼,以解析 [JsonProperty] 屬性參考:

    using Newtonsoft.Json;
    
  5. 重複測試 Web API 一節中定義的步驟。 請注意 JSON 屬性名稱中的差異。

將驗證支援新增至 Web API

ASP.NET Core Identity 會將使用者介面 (UI) 登入功能新增至 ASP.NET Core Web 應用程式。 若要保護 Web API 和 SPA,請使用下列其中一項:

Duende Identity伺服器是適用於 ASP.NET Core 的 OpenID Connect 和 OAuth 2.0 架構。 Duende Identity伺服器會啟用下列安全性功能:

  • 驗證即服務 (AaaS)
  • 多個應用程式類型的單一登入/登出 (SSO)
  • API 的存取控制
  • Federation Gateway

如需詳細資訊,請參閱 Duende Identity伺服器概觀。

如需其他驗證提供者的詳細資訊,請參閱 ASP.NET Core 的社群 OSS 驗證選項

下一步

如需有關建置 ASP.NET Core Web API 的詳細資訊,請參閱下列資源: