作者 Pratik Khandelwal Scott Addie

本教程创建对 MongoDB NoSQL 数据库运行创建、读取、更新和删除 (CRUD) 操作的 Web API。

在本教程中,你将了解:

  • 配置 MongoDB
  • 创建 MongoDB 数据库
  • 定义 MongoDB 集合和架构
  • 从 Web API 执行 MongoDB CRUD 操作
  • 自定义 JSON 序列化
  • MongoDB 6.0.5 或更高版本
  • MongoDB Shell
  • 从开发计算机上的任意位置启用 MongoDB 和 Mongo DB Shell 访问:

  • 在 Windows 上,MongoDB 将默认安装在 C:\Program Files\MongoDB 中。 将 C:\Program Files\MongoDB\Server\ version_number>\bin 添加到 PATH 环境变量。

  • 下载 MongoDB Shell 并选择要将它提取到的目录。 将 mongosh.exe 的结果路径添加到 PATH 环境变量。

  • 选择开发计算机上用于存储数据的目录。 例如,在 Windows 上为 C:\BooksData 。 创建目录(如果不存在)。 mongo Shell 不会创建新目录。

  • 在 OS 命令行界面(而不是 MongoDB Shell)中,使用以下命令连接到默认端口 27017 上的 MongoDB。 将 <data_directory_path> 替换为上一步中选择的目录。

    mongod --dbpath <data_directory_path>
    

    在以下步骤中使用之前安装的 MongoDB Shell 可以创建数据库、创建集合和存储文档。 有关 MongoDB Shell 命令的详细信息,请参阅 mongosh

  • 通过启动 mongosh.exe 打开 MongoDB 命令行界面实例。

  • 在命令行界面中,通过运行以下命令连接到默认的测试数据库:

    mongosh
    
  • 在命令行界面中运行以下命令:

    use BookStore
    

    如果它不存在,则创建名为 BookStore 的数据库。 如果该数据库存在,则将为事务打开其连接。

  • 使用以下命令创建 Books 集合:

    db.createCollection('Books')
    

    显示以下结果:

    { "ok" : 1 }
    
  • 使用以下命令定义 Books 集合的架构并插入两个文档:

    db.Books.insertMany([{ "Name": "Design Patterns", "Price": 54.93, "Category": "Computers", "Author": "Ralph Johnson" }, { "Name": "Clean Code", "Price": 43.15, "Category": "Computers","Author": "Robert C. Martin" }])
    

    显示的结果如下所示:

    "acknowledged" : true, "insertedIds" : [ ObjectId("61a6058e6c43f32854e51f51"), ObjectId("61a6058e6c43f32854e51f52")

    前面结果中显示的 ObjectId 与命令行界面中显示的结果不一致。

  • 使用以下命令查看数据库中的文档:

    db.Books.find().pretty()
    

    显示的结果如下所示:

    "_id" : ObjectId("61a6058e6c43f32854e51f51"), "Name" : "Design Patterns", "Price" : 54.93, "Category" : "Computers", "Author" : "Ralph Johnson" "_id" : ObjectId("61a6058e6c43f32854e51f52"), "Name" : "Clean Code", "Price" : 43.15, "Category" : "Computers", "Author" : "Robert C. Martin"

    该架构将为每个文档添加类型 ObjectId 的自动生成的 _id 属性。

    创建 ASP.NET Core Web API 项目

    Visual Studio Visual Studio Code Visual Studio for Mac

    上述命令将生成新的 ASP.NET Core Web API 项目,然后在 Visual Studio Code 中打开该项目。

  • OmniSharp 服务器启动后,对话框将询问“'BookStoreApi' 缺少生成和调试所需的资产。是否添加它们?”。 选择 “是”

  • 打开“集成终端”并运行以下命令,以安装适用于 MongoDB 的 .NET 驱动程序:

    dotnet add package MongoDB.Driver
    
  • 从边栏中依次选择“文件”>“新建解决方案”>“Web 和控制台”>“应用”。
  • 依次选择“ASP.NET Core”“API”C# 项目模板,然后选择“下一步”。
  • 从“目标框架”下拉列表中选择“.NET 6.0”,然后选择“下一步”。
  • 输入“BookStoreApi”作为“项目名称”,然后选择“创建”。
  • 在“解决方案”面板中,右键单击项目的“依赖项”节点,然后选择“添加包”。
  • 在搜索框中输入“MongoDB.Driver”,选择“MongoDB.Driver”包,然后选择“添加包” 。
  • 在“许可证接受”对话框中,选择“接受”按钮 。
  • 添加实体模型

  • 将 Models 目录添加到项目根。

  • 使用以下代码将 Book 类添加到 Models 目录:

    using MongoDB.Bson; using MongoDB.Bson.Serialization.Attributes; namespace BookStoreApi.Models; public class Book [BsonId] [BsonRepresentation(BsonType.ObjectId)] public string? Id { get; set; } [BsonElement("Name")] public string BookName { get; set; } = null!; public decimal Price { get; set; } public string Category { get; set; } = null!; public string Author { get; set; } = null!;

    在前面的类中,Id 属性为:

  • 需要在将公共语言运行时 (CLR) 对象映射到 MongoDB 集合时使用。
  • 使用 [BsonId] 进行批注,以将此属性指定为文档的主键。
  • 使用 [BsonRepresentation(BsonType.ObjectId)] 进行批注,以允许将参数作为类型 string 而非 [BsonRepresentation(BsonType.ObjectId)] 结构传递。 Mongo 处理从 stringObjectId 的转换。
  • BookName 属性使用 [BsonElement] 特性进行批注。 Name 的属性值表示 MongoDB 集合中的属性名称。

    添加配置模型

  • appsettings.json 添加以下数据库配置值:

    "BookStoreDatabase": { "ConnectionString": "mongodb://localhost:27017", "DatabaseName": "BookStore", "BooksCollectionName": "Books" "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Warning" "AllowedHosts": "*"
  • 使用以下代码将 BookStoreDatabaseSettings 类添加到 Models 目录:

    namespace BookStoreApi.Models; public class BookStoreDatabaseSettings public string ConnectionString { get; set; } = null!; public string DatabaseName { get; set; } = null!; public string BooksCollectionName { get; set; } = null!;

    前面的 BookStoreDatabaseSettings 类用于存储 appsettings.json 文件的 BookStoreDatabase 属性值。 JSON 和 C# 具有相同的属性名称,目的是简化映射过程。

  • 将以下突出显示的代码添加到 Program.cs

    var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.Configure<BookStoreDatabaseSettings>( builder.Configuration.GetSection("BookStoreDatabase"));

    在前面的代码中,appsettings.json 文件的 BookStoreDatabase 部分绑定到的配置实例在依赖关系注入 (DI) 容器中注册。 例如,BookStoreDatabaseSettings 对象的 ConnectionString 属性使用 appsettings.json 中的 BookStoreDatabase:ConnectionString 属性进行填充。

  • 将以下代码添加到 Program.cs 的顶部以解析 BookStoreDatabaseSettings 引用:

    using BookStoreApi.Models;

    添加 CRUD 操作服务

  • 将 Services 目录添加到项目根。

  • 使用以下代码将 BooksService 类添加到 Services 目录:

    using BookStoreApi.Models; using Microsoft.Extensions.Options; using MongoDB.Driver; namespace BookStoreApi.Services; public class BooksService private readonly IMongoCollection<Book> _booksCollection; public BooksService( IOptions<BookStoreDatabaseSettings> bookStoreDatabaseSettings) var mongoClient = new MongoClient( bookStoreDatabaseSettings.Value.ConnectionString); var mongoDatabase = mongoClient.GetDatabase( bookStoreDatabaseSettings.Value.DatabaseName); _booksCollection = mongoDatabase.GetCollection<Book>( bookStoreDatabaseSettings.Value.BooksCollectionName); public async Task<List<Book>> GetAsync() => await _booksCollection.Find(_ => true).ToListAsync(); public async Task<Book?> GetAsync(string id) => await _booksCollection.Find(x => x.Id == id).FirstOrDefaultAsync(); public async Task CreateAsync(Book newBook) => await _booksCollection.InsertOneAsync(newBook); public async Task UpdateAsync(string id, Book updatedBook) => await _booksCollection.ReplaceOneAsync(x => x.Id == id, updatedBook); public async Task RemoveAsync(string id) => await _booksCollection.DeleteOneAsync(x => x.Id == id);

    上面的代码通过构造函数注入从 DI 检索 BookStoreDatabaseSettings 实例。 使用此方法可访问在添加配置模型部分中添加的 配置值。

  • 将以下突出显示的代码添加到 Program.cs

    var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.Configure<BookStoreDatabaseSettings>( builder.Configuration.GetSection("BookStoreDatabase")); builder.Services.AddSingleton<BooksService>();

    上面的代码向 DI 注册了 BooksService 类,以支持消费类中的构造函数注入。 单一实例服务生存期是最合适的,因为 BooksService 直接依赖于 MongoClient。 根据官方 Mongo Client 重用准则,应使用单一实例服务生存期在 DI 中注册

  • 将以下代码添加到 Program.cs 的顶部以解析 BooksService 引用:

    using BookStoreApi.Services;

    BooksService 类使用以下 MongoDB.Driver 成员对数据库运行 CRUD 操作:

  • MongoClient:读取用于运行数据库操作的服务器实例。 此类的构造函数提供了 MongoDB 连接字符串:

    public BooksService( IOptions<BookStoreDatabaseSettings> bookStoreDatabaseSettings) var mongoClient = new MongoClient( bookStoreDatabaseSettings.Value.ConnectionString); var mongoDatabase = mongoClient.GetDatabase( bookStoreDatabaseSettings.Value.DatabaseName); _booksCollection = mongoDatabase.GetCollection<Book>( bookStoreDatabaseSettings.Value.BooksCollectionName);
  • IMongoDatabase:表示用于运行操作的 Mongo 数据库。 本教程在界面上使用泛型 GetCollectionTDocument>(collection) 方法来获取对特定集合中数据的访问权限。 调用此方法后,对集合运行 CRUD 操作。 在 GetCollection<TDocument>(collection) 方法调用中:

  • collection 表示集合名称。
  • TDocument 表示存储在集合中的 CLR 对象类型。
  • GetCollection<TDocument>(collection) 返回表示集合的 GetCollection<TDocument>(collection) 对象。 在本教程中,对集合调用以下方法:

  • DeleteOneAsync:删除与提供的搜索条件匹配的单个文档。
  • FindTDocument>:返回集合中与提供的搜索条件匹配的所有文档。
  • 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,以返回 CreatedAtAction 响应。 状态代码 201 是在服务器上创建新资源的 HTTP POST 方法的标准响应。 CreatedAtAction 还会将 Location 标头添加到响应中。 Location 标头指定新建书籍的 URI。
  • 测试 Web API

  • 生成并运行应用。

  • 导航到 https://localhost:<port>/api/books,其中 <port> 是应用自动分配的端口号,用于测试控制器的无参数 Get 操作方法。 显示类似下面的 JSON 响应:

    "id": "61a6058e6c43f32854e51f51", "bookName": "Design Patterns", "price": 54.93, "category": "Computers", "author": "Ralph Johnson" "id": "61a6058e6c43f32854e51f52", "bookName": "Clean Code", "price": 43.15, "category": "Computers", "author": "Robert C. Martin"
  • 导航到 https://localhost:<port>/api/books/{id here},测试控制器的重载 Get 操作方法。 显示类似下面的 JSON 响应:

    "id": "61a6058e6c43f32854e51f52", "bookName": "Clean Code", "price": 43.15, "category": "Computers", "author": "Robert C. Martin"

    配置 JSON 序列化选项

    关于在测试 Web API 部分中返回的 JSON 响应,有两个细节需要更改:

  • 应更改属性名称的默认驼峰式大小写风格,以匹配 CLR 对象属性名称的 Pascal 大小写。
  • bookName 属性应作为 Name 返回。
  • 为满足上述要求,请进行以下更改:

  • Program.cs 中,将以下突出显示的代码链接到 AddControllers 方法调用:

    var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.Configure<BookStoreDatabaseSettings>( builder.Configuration.GetSection("BookStoreDatabase")); builder.Services.AddSingleton<BooksService>(); builder.Services.AddControllers() .AddJsonOptions( options => options.JsonSerializerOptions.PropertyNamingPolicy = null);

    通过上述更改,Web API 的序列化 JSON 响应中的属性名称与 CLR 对象类型中其相应的属性名称匹配。 例如,Book 类的 Author 属性序列化为 Author,而不是 author

  • Models/Book.cs 中,使用 [JsonPropertyName] 特性批注 BookName 属性:

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

    [JsonPropertyName] 属性的 Name 值表示 Web API 的序列化 JSON 响应中的属性名称。

  • 将以下代码添加到 Models/Book.cs 的顶部以解析 [JsonProperty] 特性引用:

    using System.Text.Json.Serialization;
  • 重复测试 Web API 部分中定义的步骤。 注意 JSON 属性名称中的区别。

    向 Web API 添加身份验证支持

    ASP.NET Core Identity 将用户界面 (UI) 登录功能添加到 ASP.NET Core Web 应用。 若要保护 Web API 和 SPA,请使用以下项之一:

  • Azure Active Directory
  • Azure Active Directory B2C (Azure AD B2C)
  • Duende Identity Server
  • Duende Identity Server 是适用于 ASP.NET Core 的 OpenID Connect 和 OAuth 2.0 框架。 Duende Identity Server 支持以下安全功能:

  • 身份验证即服务 (AaaS)
  • 跨多个应用程序类型的单一登录/注销 (SSO)
  • API 的访问控制
  • Federation Gateway
  • Duende Software 可能会要求你为 Duende Server 的生产使用支付许可证费用。 有关详细信息,请参阅从 ASP.NET Core 5.0 迁移到 6.0

    有关详细信息,请参阅 Duende Server 文档(Duende Software 网站)。

  • 查看或下载示例代码如何下载
  • 使用 ASP.NET Core 创建 Web API
  • ASP.NET Core Web API 中控制器操作的返回类型
  • 使用 ASP.NET Core 创建 Web API
  • 本教程创建对 MongoDB NoSQL 数据库运行创建、读取、更新和删除 (CRUD) 操作的 Web API。

    在本教程中,你将了解:

  • 配置 MongoDB
  • 创建 MongoDB 数据库
  • 定义 MongoDB 集合和架构
  • 从 Web API 执行 MongoDB CRUD 操作
  • 自定义 JSON 序列化
  • 查看或下载示例代码如何下载

    Visual Studio Visual Studio Code Visual Studio for Mac

    配置 MongoDB

    如果使用的是 Windows,MongoDB 将默认安装在 C:\Program Files\MongoDB 中。 将 C:\Program Files\MongoDB\Server\version_number>\bin 添加到 Path 环境变量。 通过此更改可以从开发计算机上的任意位置访问 MongoDB。

    使用以下步骤中的 mongo Shell 可以创建数据库、创建集合和存储文档。 有关 mongo Shell 命令的详细信息,请参阅使用 mongo Shell

  • 选择开发计算机上用于存储数据的目录。 例如,在 Windows 上为 C:\BooksData。 创建目录(如果不存在)。 mongo Shell 不会创建新目录。

  • 打开命令行界面。 运行以下命令以连接到默认端口 27017 上的 MongoDB。 请记得将 <data_directory_path> 替换为上一步中选择的目录。

    mongod --dbpath <data_directory_path>
    
  • 打开另一个命令行界面实例。 通过运行以下命令来连接到默认测试数据库:

    mongo
    
  • 在命令行界面中运行以下命令:

    use BookstoreDb
    

    如果它不存在,则将创建名为“BookstoreDb”的数据库。 如果该数据库存在,则将为事务打开其连接。

  • 使用以下命令创建 Books 集合:

    db.createCollection('Books')
    

    显示以下结果:

    { "ok" : 1 }
    
  • 使用以下命令定义 Books 集合的架构并插入两个文档:

    db.Books.insertMany([{'Name':'Design Patterns','Price':54.93,'Category':'Computers','Author':'Ralph Johnson'}, {'Name':'Clean Code','Price':43.15,'Category':'Computers','Author':'Robert C. Martin'}])
    

    显示以下结果:

    "acknowledged" : true, "insertedIds" : [ ObjectId("5bfd996f7b8e48dc15ff215d"), ObjectId("5bfd996f7b8e48dc15ff215e")

    本文所示的 ID 与运行此示例时的 ID 不匹配。

  • 使用以下命令查看数据库中的文档:

    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"

    该架构将为每个文档添加类型 ObjectId 的自动生成的 _id 属性。

    数据库可供使用了。 你可以开始创建 ASP.NET Core Web API。

    创建 ASP.NET Core Web API 项目

    Visual Studio Visual Studio Code Visual Studio for Mac
  • 选择“.NET Core”目标框架和“ASP.NET Core 3.0”。 选择“API”项目模板,然后选择“创建” 。

  • 访问 NuGet 库:MongoDB.Driver 来确定适用于 MongoDB 的 .NET 驱动程序的最新稳定版本。 在“包管理器控制台”窗口中,导航到项目根。 运行以下命令以安装适用于 MongoDB 的 .NET 驱动程序:

    Install-Package MongoDB.Driver -Version {VERSION}
    

    将在 Visual Studio Code 中生成并打开以 .NET Core 为目标的新 ASP.NET Core Web API 项目。

  • 状态栏的 OmniSharp 火焰图标变绿后,对话框将询问“'BooksApi' 缺少生成和调试所需的资产。是否添加它们?”。 选择 “是”

  • 访问 NuGet 库:MongoDB.Driver 来确定适用于 MongoDB 的 .NET 驱动程序的最新稳定版本。 打开“集成终端”并导航到项目根。 运行以下命令以安装适用于 MongoDB 的 .NET 驱动程序:

    dotnet add BooksApi.csproj package MongoDB.Driver -v {VERSION}
    
  • 在早于版本 8.6 的 Visual Studio for Mac 中,从边栏中依次选择“文件”“新建解决方案”“.NET Core”“应用”。 在版本 8.6 或更高版本中,从边栏中依次选择“文件”“新建解决方案”“Web 和控制台”“应用”。
  • 依次选择“ASP.NET Core”“API”C# 项目模板,然后选择“下一步”。
  • 从“目标框架”下拉列表中选择“.NET Core 3.1”,然后选择“下一步” 。
  • 输入“BooksApi”作为“项目名称”,然后选择“创建” 。
  • 在“解决方案”面板中,右键单击项目的“依赖项”节点,然后选择“添加包”。
  • 在搜索框中输入“MongoDB.Driver”,选择“MongoDB.Driver”包,然后选择“添加包” 。
  • 在“许可证接受”对话框中,选择“接受”按钮 。
  • 添加实体模型

  • 将 Models 目录添加到项目根。

  • 使用以下代码将 Book 类添加到 Models 目录:

    using MongoDB.Bson;
    using MongoDB.Bson.Serialization.Attributes;
    namespace BooksApi.Models
        public class Book
            [BsonId]
            [BsonRepresentation(BsonType.ObjectId)]
            public string Id { get; set; }
            [BsonElement("Name")]
            public string BookName { get; set; }
            public decimal Price { get; set; }
            public string Category { get; set; }
            public string Author { get; set; }
    

    在前面的类中,Id 属性为:

  • 需要在将公共语言运行时 (CLR) 对象映射到 MongoDB 集合时使用。
  • 使用 [BsonId] 进行批注,以将此属性指定为文档的主键。
  • 使用 [BsonRepresentation(BsonType.ObjectId)] 进行批注,以允许将参数作为类型 string 而非 [BsonRepresentation(BsonType.ObjectId)] 结构传递。 Mongo 处理从 stringObjectId 的转换。
  • BookName 属性使用 [BsonElement] 特性进行批注。 Name 的属性值表示 MongoDB 集合中的属性名称。

    添加配置模型

  • appsettings.json 添加以下数据库配置值:

    "BookstoreDatabaseSettings": { "BooksCollectionName": "Books", "ConnectionString": "mongodb://localhost:27017", "DatabaseName": "BookstoreDb" "Logging": { "IncludeScopes": false, "Debug": { "LogLevel": { "Default": "Warning" "Console": { "LogLevel": { "Default": "Warning"
  • 使用以下代码将 BookstoreDatabaseSettings.cs 文件添加到 Models 目录:

    namespace BooksApi.Models public class BookstoreDatabaseSettings : IBookstoreDatabaseSettings public string BooksCollectionName { get; set; } public string ConnectionString { get; set; } public string DatabaseName { get; set; } public interface IBookstoreDatabaseSettings string BooksCollectionName { get; set; } string ConnectionString { get; set; } string DatabaseName { get; set; }

    前面的 BookstoreDatabaseSettings 类用于存储 appsettings.json 文件的 BookstoreDatabaseSettings 属性值。 JSON 和 C# 具有相同的属性名称,目的是简化映射过程。

  • 将以下突出显示的代码添加到 Startup.ConfigureServices

    public void ConfigureServices(IServiceCollection services) // requires using Microsoft.Extensions.Options services.Configure<BookstoreDatabaseSettings>( Configuration.GetSection(nameof(BookstoreDatabaseSettings))); services.AddSingleton<IBookstoreDatabaseSettings>(sp => sp.GetRequiredService<IOptions<BookstoreDatabaseSettings>>().Value); services.AddControllers();

    在上述代码中:

  • appsettings.json 文件的 BookstoreDatabaseSettings 部分绑定到的配置实例在依赖关系注入 (DI) 容器中注册。 例如,BookstoreDatabaseSettings 对象的 ConnectionString 属性使用 appsettings.json 中的 BookstoreDatabaseSettings:ConnectionString 属性进行填充。
  • IBookstoreDatabaseSettings 接口使用单一实例IBookstoreDatabaseSettings在 DI 中注册。 在注入时,接口实例时将解析为 BookstoreDatabaseSettings 对象。
  • 将以下代码添加到 Startup.cs 的顶部以解析 BookstoreDatabaseSettingsIBookstoreDatabaseSettings 引用:

    using BooksApi.Models;

    添加 CRUD 操作服务

  • 将 Services 目录添加到项目根。

  • 使用以下代码将 BookService 类添加到 Services 目录:

    using BooksApi.Models; using MongoDB.Driver; using System.Collections.Generic; using System.Linq; namespace BooksApi.Services public class BookService private readonly IMongoCollection<Book> _books; public BookService(IBookstoreDatabaseSettings settings) var client = new MongoClient(settings.ConnectionString); var database = client.GetDatabase(settings.DatabaseName); _books = database.GetCollection<Book>(settings.BooksCollectionName); public List<Book> Get() => _books.Find(book => true).ToList(); public Book Get(string id) => _books.Find<Book>(book => book.Id == id).FirstOrDefault(); public Book Create(Book book) _books.InsertOne(book); return book; public void Update(string id, Book bookIn) => _books.ReplaceOne(book => book.Id == id, bookIn); public void Remove(Book bookIn) => _books.DeleteOne(book => book.Id == bookIn.Id); public void Remove(string id) => _books.DeleteOne(book => book.Id == id);

    上面的代码通过构造函数注入从 DI 检索 IBookstoreDatabaseSettings 实例。 使用此方法可访问在添加配置模型部分中添加的 配置值。

  • 将以下突出显示的代码添加到 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();

    上面的代码向 DI 注册了 BookService 类,以支持消费类中的构造函数注入。 单一实例服务生存期是最合适的,因为 BookService 直接依赖于 MongoClient。 根据官方 Mongo Client 重用准则,应使用单一实例服务生存期在 DI 中注册

  • 将以下代码添加到 Startup.cs 的顶部以解析 BookService 引用:

    using BooksApi.Services;

    BookService 类使用以下 MongoDB.Driver 成员对数据库运行 CRUD 操作:

  • MongoClient:读取用于运行数据库操作的服务器实例。 此类的构造函数提供了 MongoDB 连接字符串:

    public BookService(IBookstoreDatabaseSettings settings) var client = new MongoClient(settings.ConnectionString); var database = client.GetDatabase(settings.DatabaseName); _books = database.GetCollection<Book>(settings.BooksCollectionName);
  • IMongoDatabase:表示用于运行操作的 Mongo 数据库。 本教程在界面上使用泛型 GetCollectionTDocument>(collection) 方法来获取对特定集合中数据的访问权限。 调用此方法后,对集合运行 CRUD 操作。 在 GetCollection<TDocument>(collection) 方法调用中:

  • collection 表示集合名称。
  • TDocument 表示存储在集合中的 CLR 对象类型。
  • GetCollection<TDocument>(collection) 返回表示集合的 GetCollection<TDocument>(collection) 对象。 在本教程中,对集合调用以下方法:

  • DeleteOne:删除与提供的搜索条件匹配的单个文档。
  • FindTDocument>:返回集合中与提供的搜索条件匹配的所有文档。
  • 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,以返回 CreatedAtRoute 响应。 状态代码 201 是在服务器上创建新资源的 HTTP POST 方法的标准响应。 CreatedAtRoute 还会将 Location 标头添加到响应中。 Location 标头指定新建书籍的 URI。
  • 测试 Web API

  • 生成并运行应用。

  • 导航到 https://localhost:<port>/api/books,测试控制器的无参数 Get 操作方法。 将显示下面的 JSON 响应:

    "id":"5bfd996f7b8e48dc15ff215d", "bookName":"Design Patterns", "price":54.93, "category":"Computers", "author":"Ralph Johnson" "id":"5bfd996f7b8e48dc15ff215e", "bookName":"Clean Code", "price":43.15, "category":"Computers", "author":"Robert C. Martin"
  • 导航到 https://localhost:<port>/api/books/{id here},测试控制器的重载 Get 操作方法。 将显示下面的 JSON 响应:

    "id":"{ID}", "bookName":"Clean Code", "price":43.15, "category":"Computers", "author":"Robert C. Martin"

    配置 JSON 序列化选项

    关于在测试 Web API 部分中返回的 JSON 响应,有两个细节需要更改:

  • 应更改属性名称的默认驼峰式大小写风格,以匹配 CLR 对象属性名称的 Pascal 大小写。
  • bookName 属性应作为 Name 返回。
  • 为满足上述要求,请进行以下更改:

  • Json.NET 已从 ASP.NET 共享框架中删除。 将包引用添加到 Microsoft.AspNetCore.Mvc.NewtonsoftJson

  • Startup.ConfigureServices 中,将以下突出显示的代码链接到 AddControllers 方法调用:

    public void ConfigureServices(IServiceCollection services) services.Configure<BookstoreDatabaseSettings>( Configuration.GetSection(nameof(BookstoreDatabaseSettings))); services.AddSingleton<IBookstoreDatabaseSettings>(sp => sp.GetRequiredService<IOptions<BookstoreDatabaseSettings>>().Value); services.AddSingleton<BookService>(); services.AddControllers() .AddNewtonsoftJson(options => options.UseMemberCasing());

    通过上述更改,Web API 的序列化 JSON 响应中的属性名称与 CLR 对象类型中其相应的属性名称匹配。 例如,Book 类的 Author 属性序列化为 Author

  • Models/Book.cs 中,使用以下 [JsonProperty] 特性批注 BookName 属性:

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

    [JsonProperty] 属性的 Name 值表示 Web API 的序列化 JSON 响应中的属性名称。

  • 将以下代码添加到 Models/Book.cs 的顶部以解析 [JsonProperty] 特性引用:

    using Newtonsoft.Json;
  • 重复测试 Web API 部分中定义的步骤。 注意 JSON 属性名称中的区别。

    向 Web API 添加身份验证支持

    ASP.NET Core Identity 将用户界面 (UI) 登录功能添加到 ASP.NET Core Web 应用。 若要保护 Web API 和 SPA,请使用以下项之一:

  • Azure Active Directory
  • Azure Active Directory B2C (Azure AD B2C)
  • Duende IdentityServer。 Duende IdentityServer 是第三方产品。
  • Duende IdentityServer 是适用于 ASP.NET Core 的 OpenID Connect 和 OAuth 2.0 框架。 Duende IdentityServer 支持以下安全功能:

  • 身份验证即服务 (AaaS)
  • 跨多个应用程序类型的单一登录/注销 (SSO)
  • API 的访问控制
  • Federation Gateway
  • 有关详细信息,请参阅 Duende IdentityServer 概述

    有关其他身份验证提供程序的详细信息,请参阅适用于 ASP.NET Core 的社区 OSS 身份验证选项

    有关构建 ASP.NET Core Web API 的详细信息,请参阅以下资源:

  • 本文的 YouTube 版本
  • 使用 ASP.NET Core 创建 Web API
  • ASP.NET Core Web API 中控制器操作的返回类型
  • 使用 ASP.NET Core 创建 Web API
  •