共用方式為


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

注意

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

警告

不再支援此版本的 ASP.NET Core。 如需詳細資訊,請參閱 .NET 和 .NET Core 支持原則。 如需目前的版本,請參閱 本文的 .NET 9 版本

重要

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

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

普拉提克·汗德爾瓦爾斯科特·阿迪

本教學課程會建立 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 Shell (mongosh.exe) 安裝在 C:\Users\<user>\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 命令殼層實例:

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

    use BookStore
    

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

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

    db.createCollection('Books')
    

    顯示的結果如下:

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

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

    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 9.0(標準支援期)
  • 請確認 [使用控制器] 的核取方塊已被勾選。
  • 確認已核取 [啟用 OpenAPI 支援 ] 複選框。
  • 選擇建立
  1. 在 [套件管理員主控台] 視窗中,瀏覽到專案根目錄。 執行下列命令以安裝適用於 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 屬性會填入 BookStoreDatabase:ConnectionString 中的 appsettings.json 屬性。

  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);
    }
    

    在前面的程式碼中,一個 BookStoreDatabaseSettings 執行個體是透過建構子注入從 DI 取得的。 此技術可讓您存取在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 中的單例服務存留期。

  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:刪除符合所提供搜尋準則的單一檔。
  • 找到<TDocument>:傳回集合中符合所提供搜尋準則的所有檔。
  • InsertOneAsync:將提供的 物件插入為集合中的新檔。
  • ReplaceOneAsync:將符合所提供搜尋準則的單一檔取代為提供的物件。

新增控制器

使用下列程式代碼將類別 BooksController 新增至 Controllers 目錄:

using BookStoreApi.Models;
using BookStoreApi.Services;
using Microsoft.AspNetCore.Mvc;

namespace BookStoreApi.Controllers;

[ApiController]
[Route("api/[controller]")]
public class BooksController : ControllerBase
{
    private readonly BooksService _booksService;

    public BooksController(BooksService booksService) =>
        _booksService = booksService;

    [HttpGet]
    public async Task<List<Book>> Get() =>
        await _booksService.GetAsync();

    [HttpGet("{id:length(24)}")]
    public async Task<ActionResult<Book>> Get(string id)
    {
        var book = await _booksService.GetAsync(id);

        if (book is null)
        {
            return NotFound();
        }

        return book;
    }

    [HttpPost]
    public async Task<IActionResult> Post(Book newBook)
    {
        await _booksService.CreateAsync(newBook);

        return CreatedAtAction(nameof(Get), new { id = newBook.Id }, newBook);
    }

    [HttpPut("{id:length(24)}")]
    public async Task<IActionResult> Update(string id, Book updatedBook)
    {
        var book = await _booksService.GetAsync(id);

        if (book is null)
        {
            return NotFound();
        }

        updatedBook.Id = book.Id;

        await _booksService.UpdateAsync(id, updatedBook);

        return NoContent();
    }

    [HttpDelete("{id:length(24)}")]
    public async Task<IActionResult> Delete(string id)
    {
        var book = await _booksService.GetAsync(id);

        if (book is null)
        {
            return NotFound();
        }

        await _booksService.RemoveAsync(id);

        return NoContent();
    }
}

之前的 Web API 控制器。

  • 使用 BooksService 類別來執行 CRUD 作業。
  • 包含動作方法以支援 GET、POST、PUT 與 DELETE HTTP 要求。
  • CreatedAtAction 動作方法中呼叫 Create,以傳回 HTTP 201 回應。 對於可在伺服器上建立新資源的 HTTP POST 方法,其標準回應是狀態碼 201。 CreatedAtAction 也會將 Location 標頭新增至回應。 Location 標頭指定新建書籍的 URI。

設定 JSON 序列化選項

有兩個細節需要變更,此變更涉及在「測試 Web API」章節中傳回的 JSON 回應。

  • 屬性名稱的預設駝峰式大小寫應更改,使其符合 CLR 物件屬性的 Pascal 大小寫。
  • bookName 屬性應傳回為 Name

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

  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

本教學課程使用 端點總管和 .HTTP 檔案 來測試 API。

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

  2. [端點總管] 中,以滑鼠右鍵按兩下第一個 GET 端點 /api/books,然後選取 [ 產生要求]。

    下列內容會新增至 BookStoreApi.http 檔案。 如果這是第一次產生要求,則會在專案根目錄中建立檔案。

    @BookStoreApi_HostAddress = https://localhost:<port>
    
    GET {{BookStoreApi_HostAddress}}/api/books
    
    ###
    

    連接埠號碼應該已經設定為應用程式所使用的埠,例如 https://localhost:56874。 如果不是這種情況,當您啟動應用程式時,可以在輸出視窗中找到您的埠號碼。

  3. 選取新要求行上方的 GET] 連結。

    GET 要求會傳送至應用程式,而回應會顯示在 [回應] 窗格中。

  4. ** 回應內容會顯示 JSON 結果,其中包含類似下列的書籍條目:

    [
      {
        "Id": "61a6058e6c43f32854e51f51",
        "Name": "Design Patterns",
        "Price": 54.93,
        "Category": "Computers",
        "Author": "Ralph Johnson"
      },
      {
        "Id": "61a6058e6c43f32854e51f52",
        "Name": "Clean Code",
        "Price": 43.15,
        "Category": "Computers",
        "Author": "Robert C. Martin"
      }
    ]
    
  5. 若要取得單一書籍,請在 /api/books/{id}, params (string id) 中以滑鼠右鍵按一下 GET 端點,然後選取 產生要求

    下列內容會附加至 BookStoreApi.http 檔案:

    @id=string
    GET {{BookStoreApi_HostAddress}}/api/books/{{id}}
    
    ###
    
  6. 以先前要求傳回的其中一個標識碼取代 id 變數,例如:

    @id="61a6058e6c43f32854e51f52"
    GET {{BookStoreApi_HostAddress}}/api/books/{{id}}
    
    ###
    
  7. 選取新要求行上方的 GET] 連結。

    GET 要求會傳送至應用程式,而回應會顯示在 [回應] 窗格中。

  8. 回應主體會顯示類似下列的 JSON:

    {
      "Id": "61a6058e6c43f32854e51f52",
      "Name": "Clean Code",
      "Price": 43.15,
      "Category": "Computers",
      "Author": "Robert C. Martin"
    }
    
  9. 若要測試 POST 端點,請以滑鼠右鍵按兩下 /api/booksPOST 端點,然後選取 [ 產生要求]。

    下列內容會新增至 BookStoreApi.http 檔案:

    POST {{BookStoreApi_HostAddress}}/api/books
    Content-Type: application/json
    
    {
      //Book
    }
    
    ###
    
  10. 將書籍評論替換為 book 物件,作為 JSON 請求的主體:

    POST {{BookStoreApi_HostAddress}}/api/books
    Content-Type: application/json
    
     {
       "Name": "The Pragmatic Programmer",
       "Price": 49.99,
       "Category": "Computers",
       "Author": "Andy Hunt"
     }
    
    ###
    
  11. 選取要求行上方的 POST] 連結。

    POST 要求會傳送至應用程式,而響應會顯示在 [ 回應 ] 窗格中。 回應應該包含新建立的書籍及其指定的ID。

  12. 最後,若要刪除書籍,請以滑鼠右鍵按兩下 /api/books/{id}, params (string id)DELETE 端點,然後選取 [ 產生要求]。

    下列內容會附加至 BookStoreApi.http 檔案:

    DELETE {{BookStoreApi_HostAddress}}/api/Books/{{id}}
    
    ###
    
  13. id 變數替換為之前的請求返回的其中一個識別碼,然後點擊 [傳送要求]。 例如:

    DELETE {{BookStoreApi_HostAddress}}/api/Books/67f417517ce1b36aeab71236
    
    ###
    

將驗證支援新增至 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 的存取控制
  • 同盟閘道

重要

Duende Software 可能會要求您支付使用 Duende Identity 伺服器的授權費用。 如需詳細資訊,請參閱 從 .NET 5 中的 ASP.NET Core 移轉至 .NET 6

如需詳細資訊,請參閱 Duende 伺服器檔(Duende Identity Software 網站)。

其他資源

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

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

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

必要條件

設定 MongoDB

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

  1. 下載並安裝 MongoDB Shell:

    • macOS/Linux: 選擇要擷取 MongoDB Shell 的目錄。 將針對 mongosh 產生的路徑新增至 PATH 環境變數。
    • Windows:MongoDB Shell (mongosh.exe) 安裝在 C:\Users\<user>\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 命令殼層實例:

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

    use BookStore
    

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

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

    db.createCollection('Books')
    

    顯示的結果如下:

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

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

    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 屬性會填入 BookStoreDatabase:ConnectionString 中的 appsettings.json 屬性。

  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);
    }
    

    在前面的程式碼中,一個 BookStoreDatabaseSettings 執行個體是透過建構子注入從 DI 取得的。 此技術可讓您存取在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 中的單例服務存留期。

  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:刪除符合所提供搜尋準則的單一檔。
  • 找到<TDocument>:傳回集合中符合所提供搜尋準則的所有檔。
  • InsertOneAsync:將提供的 物件插入為集合中的新檔。
  • ReplaceOneAsync:將符合所提供搜尋準則的單一檔取代為提供的物件。

新增控制器

使用下列程式代碼將類別 BooksController 新增至 Controllers 目錄:

using BookStoreApi.Models;
using BookStoreApi.Services;
using Microsoft.AspNetCore.Mvc;

namespace BookStoreApi.Controllers;

[ApiController]
[Route("api/[controller]")]
public class BooksController : ControllerBase
{
    private readonly BooksService _booksService;

    public BooksController(BooksService booksService) =>
        _booksService = booksService;

    [HttpGet]
    public async Task<List<Book>> Get() =>
        await _booksService.GetAsync();

    [HttpGet("{id:length(24)}")]
    public async Task<ActionResult<Book>> Get(string id)
    {
        var book = await _booksService.GetAsync(id);

        if (book is null)
        {
            return NotFound();
        }

        return book;
    }

    [HttpPost]
    public async Task<IActionResult> Post(Book newBook)
    {
        await _booksService.CreateAsync(newBook);

        return CreatedAtAction(nameof(Get), new { id = newBook.Id }, newBook);
    }

    [HttpPut("{id:length(24)}")]
    public async Task<IActionResult> Update(string id, Book updatedBook)
    {
        var book = await _booksService.GetAsync(id);

        if (book is null)
        {
            return NotFound();
        }

        updatedBook.Id = book.Id;

        await _booksService.UpdateAsync(id, updatedBook);

        return NoContent();
    }

    [HttpDelete("{id:length(24)}")]
    public async Task<IActionResult> Delete(string id)
    {
        var book = await _booksService.GetAsync(id);

        if (book is null)
        {
            return NotFound();
        }

        await _booksService.RemoveAsync(id);

        return NoContent();
    }
}

之前的 Web API 控制器。

  • 使用 BooksService 類別來執行 CRUD 作業。
  • 包含動作方法以支援 GET、POST、PUT 與 DELETE HTTP 要求。
  • CreatedAtAction 動作方法中呼叫 Create,以傳回 HTTP 201 回應。 對於可在伺服器上建立新資源的 HTTP POST 方法,其標準回應是狀態碼 201。 CreatedAtAction 也會將 Location 標頭新增至回應。 Location 標頭指定新建書籍的 URI。

測試 Web API

  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 的存取控制
  • 同盟閘道

重要

Duende Software 可能會要求您支付使用 Duende Identity 伺服器的授權費用。 如需詳細資訊,請參閱 從 .NET 5 中的 ASP.NET Core 移轉至 .NET 6

如需詳細資訊,請參閱 Duende 伺服器檔(Duende Identity Software 網站)。

其他資源

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

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

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

必要條件

設定 MongoDB

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

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

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

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

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

    mongod --dbpath <data_directory_path>
    

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

  1. 啟動 mongosh.exe,或在命令殼層中執行下列命令,以開啟 MongoDB 命令殼層實例:

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

    use BookStore
    

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

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

    db.createCollection('Books')
    

    顯示的結果如下:

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

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

    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 屬性會填入 BookStoreDatabase:ConnectionString 中的 appsettings.json 屬性。

  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);
    }
    

    在前面的程式碼中,一個 BookStoreDatabaseSettings 執行個體是透過建構子注入從 DI 取得的。 此技術可讓您存取在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 中的單例服務存留期。

  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:刪除符合所提供搜尋準則的單一檔。
  • 找到<TDocument>:傳回集合中符合所提供搜尋準則的所有檔。
  • InsertOneAsync:將提供的 物件插入為集合中的新檔。
  • ReplaceOneAsync:將符合所提供搜尋準則的單一檔取代為提供的物件。

新增控制器

使用下列程式代碼將類別 BooksController 新增至 Controllers 目錄:

using BookStoreApi.Models;
using BookStoreApi.Services;
using Microsoft.AspNetCore.Mvc;

namespace BookStoreApi.Controllers;

[ApiController]
[Route("api/[controller]")]
public class BooksController : ControllerBase
{
    private readonly BooksService _booksService;

    public BooksController(BooksService booksService) =>
        _booksService = booksService;

    [HttpGet]
    public async Task<List<Book>> Get() =>
        await _booksService.GetAsync();

    [HttpGet("{id:length(24)}")]
    public async Task<ActionResult<Book>> Get(string id)
    {
        var book = await _booksService.GetAsync(id);

        if (book is null)
        {
            return NotFound();
        }

        return book;
    }

    [HttpPost]
    public async Task<IActionResult> Post(Book newBook)
    {
        await _booksService.CreateAsync(newBook);

        return CreatedAtAction(nameof(Get), new { id = newBook.Id }, newBook);
    }

    [HttpPut("{id:length(24)}")]
    public async Task<IActionResult> Update(string id, Book updatedBook)
    {
        var book = await _booksService.GetAsync(id);

        if (book is null)
        {
            return NotFound();
        }

        updatedBook.Id = book.Id;

        await _booksService.UpdateAsync(id, updatedBook);

        return NoContent();
    }

    [HttpDelete("{id:length(24)}")]
    public async Task<IActionResult> Delete(string id)
    {
        var book = await _booksService.GetAsync(id);

        if (book is null)
        {
            return NotFound();
        }

        await _booksService.RemoveAsync(id);

        return NoContent();
    }
}

之前的 Web API 控制器。

  • 使用 BooksService 類別來執行 CRUD 作業。
  • 包含動作方法以支援 GET、POST、PUT 與 DELETE HTTP 要求。
  • CreatedAtAction 動作方法中呼叫 Create,以傳回 HTTP 201 回應。 對於可在伺服器上建立新資源的 HTTP POST 方法,其標準回應是狀態碼 201。 CreatedAtAction 也會將 Location 標頭新增至回應。 Location 標頭指定新建書籍的 URI。

測試 Web API

  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 的存取控制
  • 同盟閘道

重要

Duende Software 可能會要求您支付使用 Duende Identity 伺服器的授權費用。 如需詳細資訊,請參閱 從 .NET 5 中的 ASP.NET Core 移轉至 .NET 6

如需詳細資訊,請參閱 Duende 伺服器檔(Duende Identity Software 網站)。

其他資源

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

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

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

必要條件

設定 MongoDB

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

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

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

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

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

    mongod --dbpath <data_directory_path>
    

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

  1. 啟動 mongosh.exe,或在命令殼層中執行下列命令,以開啟 MongoDB 命令殼層實例:

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

    use BookStore
    

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

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

    db.createCollection('Books')
    

    顯示的結果如下:

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

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

    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 屬性會填入 BookStoreDatabase:ConnectionString 中的 appsettings.json 屬性。

  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);
    }
    

    在前面的程式碼中,一個 BookStoreDatabaseSettings 執行個體是透過建構子注入從 DI 取得的。 此技術可讓您存取在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 中的單例服務存留期。

  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:刪除符合所提供搜尋準則的單一檔。
  • 找到<TDocument>:傳回集合中符合所提供搜尋準則的所有檔。
  • InsertOneAsync:將提供的 物件插入為集合中的新檔。
  • ReplaceOneAsync:將符合所提供搜尋準則的單一檔取代為提供的物件。

新增控制器

使用下列程式代碼將類別 BooksController 新增至 Controllers 目錄:

using BookStoreApi.Models;
using BookStoreApi.Services;
using Microsoft.AspNetCore.Mvc;

namespace BookStoreApi.Controllers;

[ApiController]
[Route("api/[controller]")]
public class BooksController : ControllerBase
{
    private readonly BooksService _booksService;

    public BooksController(BooksService booksService) =>
        _booksService = booksService;

    [HttpGet]
    public async Task<List<Book>> Get() =>
        await _booksService.GetAsync();

    [HttpGet("{id:length(24)}")]
    public async Task<ActionResult<Book>> Get(string id)
    {
        var book = await _booksService.GetAsync(id);

        if (book is null)
        {
            return NotFound();
        }

        return book;
    }

    [HttpPost]
    public async Task<IActionResult> Post(Book newBook)
    {
        await _booksService.CreateAsync(newBook);

        return CreatedAtAction(nameof(Get), new { id = newBook.Id }, newBook);
    }

    [HttpPut("{id:length(24)}")]
    public async Task<IActionResult> Update(string id, Book updatedBook)
    {
        var book = await _booksService.GetAsync(id);

        if (book is null)
        {
            return NotFound();
        }

        updatedBook.Id = book.Id;

        await _booksService.UpdateAsync(id, updatedBook);

        return NoContent();
    }

    [HttpDelete("{id:length(24)}")]
    public async Task<IActionResult> Delete(string id)
    {
        var book = await _booksService.GetAsync(id);

        if (book is null)
        {
            return NotFound();
        }

        await _booksService.RemoveAsync(id);

        return NoContent();
    }
}

之前的 Web API 控制器。

  • 使用 BooksService 類別來執行 CRUD 作業。
  • 包含動作方法以支援 GET、POST、PUT 與 DELETE HTTP 要求。
  • CreatedAtAction 動作方法中呼叫 Create,以傳回 HTTP 201 回應。 對於可在伺服器上建立新資源的 HTTP POST 方法,其標準回應是狀態碼 201。 CreatedAtAction 也會將 Location 標頭新增至回應。 Location 標頭指定新建書籍的 URI。

測試 Web API

  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 的存取控制
  • 同盟閘道

重要

Duende Software 可能會要求您支付使用 Duende Identity 伺服器的授權費用。 如需詳細資訊,請參閱 從 .NET 5 中的 ASP.NET Core 移轉至 .NET 6

如需詳細資訊,請參閱 Duende 伺服器檔(Duende Identity Software 網站)。

其他資源

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

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

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

檢視或下載範例程式代碼如何下載

必要條件

設定 MongoDB

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

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

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

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

    mongod --dbpath <data_directory_path>
    
  3. 開啟另一個命令提示字元實例。 執行下列命令以連線到預設測試資料庫:

    mongo
    
  4. 在命令提示字元中執行下列命令:

    use BookstoreDb
    

    如果 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 資源庫: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 屬性會填入 BookstoreDatabaseSettings:ConnectionString 中的 appsettings.json 屬性。
    • 介面 IBookstoreDatabaseSettings 會以單態服務生命週期在 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 中的單例服務存留期。

  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:刪除符合所提供搜尋準則的單一檔。
  • 找到<TDocument>:傳回集合中符合所提供搜尋準則的所有檔。
  • InsertOne:將提供的 物件插入為集合中的新檔。
  • ReplaceOne:將符合所提供搜尋準則的單一檔取代為提供的 物件。

新增控制器

使用下列程式代碼將類別 BooksController 新增至 Controllers 目錄:

using BooksApi.Models;
using BooksApi.Services;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;

namespace BooksApi.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class BooksController : ControllerBase
    {
        private readonly BookService _bookService;

        public BooksController(BookService bookService)
        {
            _bookService = bookService;
        }

        [HttpGet]
        public ActionResult<List<Book>> Get() =>
            _bookService.Get();

        [HttpGet("{id:length(24)}", Name = "GetBook")]
        public ActionResult<Book> Get(string id)
        {
            var book = _bookService.Get(id);

            if (book == null)
            {
                return NotFound();
            }

            return book;
        }

        [HttpPost]
        public ActionResult<Book> Create(Book book)
        {
            _bookService.Create(book);

            return CreatedAtRoute("GetBook", new { id = book.Id.ToString() }, book);
        }

        [HttpPut("{id:length(24)}")]
        public IActionResult Update(string id, Book bookIn)
        {
            var book = _bookService.Get(id);

            if (book == null)
            {
                return NotFound();
            }

            _bookService.Update(id, bookIn);

            return NoContent();
        }

        [HttpDelete("{id:length(24)}")]
        public IActionResult Delete(string id)
        {
            var book = _bookService.Get(id);

            if (book == null)
            {
                return NotFound();
            }

            _bookService.Remove(id);

            return NoContent();
        }
    }
}

之前的 Web API 控制器。

  • 使用 BookService 類別來執行 CRUD 作業。
  • 包含動作方法以支援 GET、POST、PUT 與 DELETE HTTP 要求。
  • CreatedAtRoute 動作方法中呼叫 Create,以傳回 HTTP 201 回應。 對於可在伺服器上建立新資源的 HTTP POST 方法,其標準回應是狀態碼 201。 CreatedAtRoute 也會將 Location 標頭新增至回應。 Location 標頭指定新建書籍的 URI。

測試 Web API

  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 中,使用下列 BookName 屬性來標註 [JsonProperty] 屬性。

    [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 IdentityServer 是適用於 ASP.NET Core 的 OpenID Connect 和 OAuth 2.0 架構。 Duende IdentityServer 會啟用下列安全性功能:

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

如需詳細資訊,請參閱 Duende IdentityServer 概觀

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

下一步

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