使用 ASP.NET Core 和 MongoDB 创建 Web APICreate a web API with ASP.NET Core and MongoDB

本文内容

作者 Pratik KhandelwalScott Addie

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

在本教程中,你将了解:

  • 配置 MongoDB
  • 创建 MongoDB 数据库
  • 定义 MongoDB 集合和架构
  • 从 Web API 执行 MongoDB CRUD 操作
  • 自定义 JSON 序列化

查看或下载示例代码如何下载

先决条件Prerequisites

配置 MongoDBConfigure 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> 替换为上一步中选择的目录。

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

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

  • 使用以下命令创建 Books 集合:
  1. db.createCollection('Books')

显示以下结果:

  1. { "ok" : 1 }
  • 使用以下命令定义 Books 集合的架构并插入两个文档:
  1. 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'}])

显示以下结果:

  1. {
  2. "acknowledged" : true,
  3. "insertedIds" : [
  4. ObjectId("5bfd996f7b8e48dc15ff215d"),
  5. ObjectId("5bfd996f7b8e48dc15ff215e")
  6. ]
  7. }

备注

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

  • 使用以下命令查看数据库中的文档:
  1. db.Books.find({}).pretty()

显示以下结果:

  1. {
  2. "_id" : ObjectId("5bfd996f7b8e48dc15ff215d"),
  3. "Name" : "Design Patterns",
  4. "Price" : 54.93,
  5. "Category" : "Computers",
  6. "Author" : "Ralph Johnson"
  7. }
  8. {
  9. "_id" : ObjectId("5bfd996f7b8e48dc15ff215e"),
  10. "Name" : "Clean Code",
  11. "Price" : 43.15,
  12. "Category" : "Computers",
  13. "Author" : "Robert C. Martin"
  14. }

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

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

创建 ASP.NET Core Web API 项目Create the ASP.NET Core web API project

  • 转到“文件”>“新建”>“项目” 。

  • 选择“ASP.NET Core Web 应用程序”项目类型,然后选择“下一步” 。

  • 将项目命名为“BooksApi”,然后选择“创建” 。

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

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

  1. Install-Package MongoDB.Driver -Version {VERSION}
  • 在命令行界面中运行以下命令:
  1. dotnet new webapi -o BooksApi
  2. code BooksApi

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

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

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

  1. dotnet add BooksApi.csproj package MongoDB.Driver -v {VERSION}
  • 转到“文件”>“新建解决方案”>“.NET Core”>“应用” 。
  • 选择“ASP.NET Core Web API”C# 项目模板,然后选择“下一步” 。
  • 从“目标框架”下拉列表中选择“.NET Core 3.0”,然后选择“下一步” 。
  • 输入“BooksApi”作为“项目名称”,然后选择“创建” 。
  • 在“解决方案” 面板中,右键单击项目的“依赖项” 节点,然后选择“添加包” 。
  • 在搜索框中输入“MongoDB.Driver”,选择“MongoDB.Driver”包,然后选择“添加包” 。
  • 在“许可证接受”对话框中,选择“接受”按钮 。

添加实体模型Add an entity model

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

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

  1. using MongoDB.Bson;
  2. using MongoDB.Bson.Serialization.Attributes;
  3. namespace BooksApi.Models
  4. {
  5. public class Book
  6. {
  7. [BsonId]
  8. [BsonRepresentation(BsonType.ObjectId)]
  9. public string Id { get; set; }
  10. [BsonElement("Name")]
  11. public string BookName { get; set; }
  12. public decimal Price { get; set; }
  13. public string Category { get; set; }
  14. public string Author { get; set; }
  15. }
  16. }

在前面的类中,Id属性:

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

添加配置模型Add a configuration model

  • 向 appsettings.json 添加以下数据库配置值 :
  1. {
  2. "BookstoreDatabaseSettings": {
  3. "BooksCollectionName": "Books",
  4. "ConnectionString": "mongodb://localhost:27017",
  5. "DatabaseName": "BookstoreDb"
  6. },
  7. "Logging": {
  8. "IncludeScopes": false,
  9. "Debug": {
  10. "LogLevel": {
  11. "Default": "Warning"
  12. }
  13. },
  14. "Console": {
  15. "LogLevel": {
  16. "Default": "Warning"
  17. }
  18. }
  19. }
  20. }
  • 使用以下代码将 BookstoreDatabaseSettings.cs 文件添加到 Models 目录 :
  1. namespace BooksApi.Models
  2. {
  3. public class BookstoreDatabaseSettings : IBookstoreDatabaseSettings
  4. {
  5. public string BooksCollectionName { get; set; }
  6. public string ConnectionString { get; set; }
  7. public string DatabaseName { get; set; }
  8. }
  9. public interface IBookstoreDatabaseSettings
  10. {
  11. string BooksCollectionName { get; set; }
  12. string ConnectionString { get; set; }
  13. string DatabaseName { get; set; }
  14. }
  15. }

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

  • 将以下突出显示的代码添加到 Startup.ConfigureServices
  1. public void ConfigureServices(IServiceCollection services)
  2. {
  3. // requires using Microsoft.Extensions.Options
  4. services.Configure<BookstoreDatabaseSettings>(
  5. Configuration.GetSection(nameof(BookstoreDatabaseSettings)));
  6. services.AddSingleton<IBookstoreDatabaseSettings>(sp =>
  7. sp.GetRequiredService<IOptions<BookstoreDatabaseSettings>>().Value);
  8. services.AddControllers();
  9. }

在上述代码中:

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

添加 CRUD 操作服务Add a CRUD operations service

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

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

  1. using BooksApi.Models;
  2. using MongoDB.Driver;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. namespace BooksApi.Services
  6. {
  7. public class BookService
  8. {
  9. private readonly IMongoCollection<Book> _books;
  10. public BookService(IBookstoreDatabaseSettings settings)
  11. {
  12. var client = new MongoClient(settings.ConnectionString);
  13. var database = client.GetDatabase(settings.DatabaseName);
  14. _books = database.GetCollection<Book>(settings.BooksCollectionName);
  15. }
  16. public List<Book> Get() =>
  17. _books.Find(book => true).ToList();
  18. public Book Get(string id) =>
  19. _books.Find<Book>(book => book.Id == id).FirstOrDefault();
  20. public Book Create(Book book)
  21. {
  22. _books.InsertOne(book);
  23. return book;
  24. }
  25. public void Update(string id, Book bookIn) =>
  26. _books.ReplaceOne(book => book.Id == id, bookIn);
  27. public void Remove(Book bookIn) =>
  28. _books.DeleteOne(book => book.Id == bookIn.Id);
  29. public void Remove(string id) =>
  30. _books.DeleteOne(book => book.Id == id);
  31. }
  32. }

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

  • 将以下突出显示的代码添加到 Startup.ConfigureServices
  1. public void ConfigureServices(IServiceCollection services)
  2. {
  3. services.Configure<BookstoreDatabaseSettings>(
  4. Configuration.GetSection(nameof(BookstoreDatabaseSettings)));
  5. services.AddSingleton<IBookstoreDatabaseSettings>(sp =>
  6. sp.GetRequiredService<IOptions<BookstoreDatabaseSettings>>().Value);
  7. services.AddSingleton<BookService>();
  8. services.AddControllers();
  9. }

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

  • 在 Startup.cs 顶部添加以下代码,以解析 BookService 引用 :
  1. using BooksApi.Services;

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

  • MongoClient – 读取服务器实例,以执行数据库操作。此类的构造函数提供了 MongoDB 连接字符串:
  1. public BookService(IBookstoreDatabaseSettings settings)
  2. {
  3. var client = new MongoClient(settings.ConnectionString);
  4. var database = client.GetDatabase(settings.DatabaseName);
  5. _books = database.GetCollection<Book>(settings.BooksCollectionName);
  6. }
  • IMongoDatabase – 表示用于执行操作的 Mongo 数据库。本教程在界面上使用泛型 GetCollection(collection) 方法来获取对特定集合中的数据的访问权限。调用此方法后,对集合执行 CRUD 操作。在 GetCollection<TDocument>(collection) 方法调用中:

    • collection 表示集合名称。
    • TDocument 表示存储在集合中的 CLR 对象类型。

      GetCollection<TDocument>(collection) 返回表示集合的 MongoCollection 对象。在本教程中,对集合调用以下方法:
  • DeleteOne – 删除与提供的搜索条件匹配的单个文档。
  • Find – 返回集合中与提供的搜索条件匹配的所有文档。
  • InsertOne – 插入提供的对象作为集合中的新文档。
  • ReplaceOne – 将与提供的搜索条件匹配的单个文档替换为提供的对象。

添加控制器Add a controller

使用以下代码将 BooksController 类添加到 Controllers 目录:

  1. using BooksApi.Models;
  2. using BooksApi.Services;
  3. using Microsoft.AspNetCore.Mvc;
  4. using System.Collections.Generic;
  5. namespace BooksApi.Controllers
  6. {
  7. [Route("api/[controller]")]
  8. [ApiController]
  9. public class BooksController : ControllerBase
  10. {
  11. private readonly BookService _bookService;
  12. public BooksController(BookService bookService)
  13. {
  14. _bookService = bookService;
  15. }
  16. [HttpGet]
  17. public ActionResult<List<Book>> Get() =>
  18. _bookService.Get();
  19. [HttpGet("{id:length(24)}", Name = "GetBook")]
  20. public ActionResult<Book> Get(string id)
  21. {
  22. var book = _bookService.Get(id);
  23. if (book == null)
  24. {
  25. return NotFound();
  26. }
  27. return book;
  28. }
  29. [HttpPost]
  30. public ActionResult<Book> Create(Book book)
  31. {
  32. _bookService.Create(book);
  33. return CreatedAtRoute("GetBook", new { id = book.Id.ToString() }, book);
  34. }
  35. [HttpPut("{id:length(24)}")]
  36. public IActionResult Update(string id, Book bookIn)
  37. {
  38. var book = _bookService.Get(id);
  39. if (book == null)
  40. {
  41. return NotFound();
  42. }
  43. _bookService.Update(id, bookIn);
  44. return NoContent();
  45. }
  46. [HttpDelete("{id:length(24)}")]
  47. public IActionResult Delete(string id)
  48. {
  49. var book = _bookService.Get(id);
  50. if (book == null)
  51. {
  52. return NotFound();
  53. }
  54. _bookService.Remove(book.Id);
  55. return NoContent();
  56. }
  57. }
  58. }

前面的 Web API 控制器:

  • 使用 BookService 类执行 CRUD 操作。
  • 包含操作方法以支持 GET、POST、PUT 和 DELETE HTTP 请求。
  • Create 操作方法中调用 CreatedAtRoute,以返回 HTTP 201 响应。状态代码 201 是在服务器上创建新资源的 HTTP POST 方法的标准响应。CreatedAtRoute 还会将 Location 标头添加到响应中。Location 标头指定新建书籍的 URI。

测试 Web APITest the web API

  1. [
  2. {
  3. "id":"5bfd996f7b8e48dc15ff215d",
  4. "bookName":"Design Patterns",
  5. "price":54.93,
  6. "category":"Computers",
  7. "author":"Ralph Johnson"
  8. },
  9. {
  10. "id":"5bfd996f7b8e48dc15ff215e",
  11. "bookName":"Clean Code",
  12. "price":43.15,
  13. "category":"Computers",
  14. "author":"Robert C. Martin"
  15. }
  16. ]
  1. {
  2. "id":"{ID}",
  3. "bookName":"Clean Code",
  4. "price":43.15,
  5. "category":"Computers",
  6. "author":"Robert C. Martin"
  7. }

配置 JSON 序列化选项Configure JSON serialization options

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

  • 应更改属性名称的默认驼峰式大小写风格,以匹配 CLR 对象属性名称的 Pascal 大小写。
  • bookName 属性应作为 Name 返回。

为满足上述要求,请进行以下更改:

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

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

  1. public void ConfigureServices(IServiceCollection services)
  2. {
  3. services.Configure<BookstoreDatabaseSettings>(
  4. Configuration.GetSection(nameof(BookstoreDatabaseSettings)));
  5. services.AddSingleton<IBookstoreDatabaseSettings>(sp =>
  6. sp.GetRequiredService<IOptions<BookstoreDatabaseSettings>>().Value);
  7. services.AddSingleton<BookService>();
  8. services.AddControllers()
  9. .AddNewtonsoftJson(options => options.UseMemberCasing());
  10. }

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

  • 在 Models/Book.cs 中,使用以下 [JsonProperty] 特性批注 BookName 属性 :
  1. [BsonElement("Name")]
  2. [JsonProperty("Name")]
  3. public string BookName { get; set; }

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

  • 在 Models/Book.cs 顶部添加以下代码,以解析 [JsonProperty] 属性引用 :
  1. using Newtonsoft.Json;
  • 重复测试 Web API 部分中定义的步骤。注意 JSON 属性名称中的区别。

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

在本教程中,你将了解:

  • 配置 MongoDB
  • 创建 MongoDB 数据库
  • 定义 MongoDB 集合和架构
  • 从 Web API 执行 MongoDB CRUD 操作
  • 自定义 JSON 序列化

查看或下载示例代码如何下载

先决条件Prerequisites

配置 MongoDBConfigure 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> 替换为上一步中选择的目录。

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

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

  • 使用以下命令创建 Books 集合:
  1. db.createCollection('Books')

显示以下结果:

  1. { "ok" : 1 }
  • 使用以下命令定义 Books 集合的架构并插入两个文档:
  1. 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'}])

显示以下结果:

  1. {
  2. "acknowledged" : true,
  3. "insertedIds" : [
  4. ObjectId("5bfd996f7b8e48dc15ff215d"),
  5. ObjectId("5bfd996f7b8e48dc15ff215e")
  6. ]
  7. }

备注

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

  • 使用以下命令查看数据库中的文档:
  1. db.Books.find({}).pretty()

显示以下结果:

  1. {
  2. "_id" : ObjectId("5bfd996f7b8e48dc15ff215d"),
  3. "Name" : "Design Patterns",
  4. "Price" : 54.93,
  5. "Category" : "Computers",
  6. "Author" : "Ralph Johnson"
  7. }
  8. {
  9. "_id" : ObjectId("5bfd996f7b8e48dc15ff215e"),
  10. "Name" : "Clean Code",
  11. "Price" : 43.15,
  12. "Category" : "Computers",
  13. "Author" : "Robert C. Martin"
  14. }

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

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

创建 ASP.NET Core Web API 项目Create the ASP.NET Core web API project

  • 转到“文件”>“新建”>“项目” 。

  • 选择“ASP.NET Core Web 应用程序”项目类型,然后选择“下一步” 。

  • 将项目命名为“BooksApi”,然后选择“创建” 。

  • 选择“.NET Core” 目标框架和“ASP.NET Core 2.2” 。选择“API”项目模板,然后选择“创建” 。

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

  1. Install-Package MongoDB.Driver -Version {VERSION}
  • 在命令行界面中运行以下命令:
  1. dotnet new webapi -o BooksApi
  2. code BooksApi

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

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

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

  1. dotnet add BooksApi.csproj package MongoDB.Driver -v {VERSION}
  • 转到“文件”>“新建解决方案”>“.NET Core”>“应用” 。
  • 选择“ASP.NET Core Web API”C# 项目模板,然后选择“下一步” 。
  • 从“目标框架”下拉列表中选择“.NET Core 2.2”,然后选择“下一步” 。
  • 输入“BooksApi”作为“项目名称”,然后选择“创建” 。
  • 在“解决方案” 面板中,右键单击项目的“依赖项” 节点,然后选择“添加包” 。
  • 在搜索框中输入“MongoDB.Driver”,选择“MongoDB.Driver”包,然后选择“添加包” 。
  • 在“许可证接受”对话框中,选择“接受”按钮 。

添加实体模型Add an entity model

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

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

  1. using MongoDB.Bson;
  2. using MongoDB.Bson.Serialization.Attributes;
  3. namespace BooksApi.Models
  4. {
  5. public class Book
  6. {
  7. [BsonId]
  8. [BsonRepresentation(BsonType.ObjectId)]
  9. public string Id { get; set; }
  10. [BsonElement("Name")]
  11. public string BookName { get; set; }
  12. public decimal Price { get; set; }
  13. public string Category { get; set; }
  14. public string Author { get; set; }
  15. }
  16. }

在前面的类中,Id属性:

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

添加配置模型Add a configuration model

  • 向 appsettings.json 添加以下数据库配置值 :
  1. {
  2. "BookstoreDatabaseSettings": {
  3. "BooksCollectionName": "Books",
  4. "ConnectionString": "mongodb://localhost:27017",
  5. "DatabaseName": "BookstoreDb"
  6. },
  7. "Logging": {
  8. "IncludeScopes": false,
  9. "Debug": {
  10. "LogLevel": {
  11. "Default": "Warning"
  12. }
  13. },
  14. "Console": {
  15. "LogLevel": {
  16. "Default": "Warning"
  17. }
  18. }
  19. }
  20. }
  • 使用以下代码将 BookstoreDatabaseSettings.cs 文件添加到 Models 目录 :
  1. namespace BooksApi.Models
  2. {
  3. public class BookstoreDatabaseSettings : IBookstoreDatabaseSettings
  4. {
  5. public string BooksCollectionName { get; set; }
  6. public string ConnectionString { get; set; }
  7. public string DatabaseName { get; set; }
  8. }
  9. public interface IBookstoreDatabaseSettings
  10. {
  11. string BooksCollectionName { get; set; }
  12. string ConnectionString { get; set; }
  13. string DatabaseName { get; set; }
  14. }
  15. }

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

  • 将以下突出显示的代码添加到 Startup.ConfigureServices
  1. public void ConfigureServices(IServiceCollection services)
  2. {
  3. services.Configure<BookstoreDatabaseSettings>(
  4. Configuration.GetSection(nameof(BookstoreDatabaseSettings)));
  5. services.AddSingleton<IBookstoreDatabaseSettings>(sp =>
  6. sp.GetRequiredService<IOptions<BookstoreDatabaseSettings>>().Value);
  7. services.AddMvc()
  8. .SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
  9. }

在上述代码中:

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

添加 CRUD 操作服务Add a CRUD operations service

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

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

  1. using BooksApi.Models;
  2. using MongoDB.Driver;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. namespace BooksApi.Services
  6. {
  7. public class BookService
  8. {
  9. private readonly IMongoCollection<Book> _books;
  10. public BookService(IBookstoreDatabaseSettings settings)
  11. {
  12. var client = new MongoClient(settings.ConnectionString);
  13. var database = client.GetDatabase(settings.DatabaseName);
  14. _books = database.GetCollection<Book>(settings.BooksCollectionName);
  15. }
  16. public List<Book> Get() =>
  17. _books.Find(book => true).ToList();
  18. public Book Get(string id) =>
  19. _books.Find<Book>(book => book.Id == id).FirstOrDefault();
  20. public Book Create(Book book)
  21. {
  22. _books.InsertOne(book);
  23. return book;
  24. }
  25. public void Update(string id, Book bookIn) =>
  26. _books.ReplaceOne(book => book.Id == id, bookIn);
  27. public void Remove(Book bookIn) =>
  28. _books.DeleteOne(book => book.Id == bookIn.Id);
  29. public void Remove(string id) =>
  30. _books.DeleteOne(book => book.Id == id);
  31. }
  32. }

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

  • 将以下突出显示的代码添加到 Startup.ConfigureServices
  1. public void ConfigureServices(IServiceCollection services)
  2. {
  3. services.Configure<BookstoreDatabaseSettings>(
  4. Configuration.GetSection(nameof(BookstoreDatabaseSettings)));
  5. services.AddSingleton<IBookstoreDatabaseSettings>(sp =>
  6. sp.GetRequiredService<IOptions<BookstoreDatabaseSettings>>().Value);
  7. services.AddSingleton<BookService>();
  8. services.AddMvc()
  9. .SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
  10. }

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

  • 在 Startup.cs 顶部添加以下代码,以解析 BookService 引用 :
  1. using BooksApi.Services;

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

  • MongoClient – 读取服务器实例,以执行数据库操作。此类的构造函数提供了 MongoDB 连接字符串:
  1. public BookService(IBookstoreDatabaseSettings settings)
  2. {
  3. var client = new MongoClient(settings.ConnectionString);
  4. var database = client.GetDatabase(settings.DatabaseName);
  5. _books = database.GetCollection<Book>(settings.BooksCollectionName);
  6. }
  • IMongoDatabase – 表示用于执行操作的 Mongo 数据库。本教程在界面上使用泛型 GetCollection(collection) 方法来获取对特定集合中的数据的访问权限。调用此方法后,对集合执行 CRUD 操作。在 GetCollection<TDocument>(collection) 方法调用中:

    • collection 表示集合名称。
    • TDocument 表示存储在集合中的 CLR 对象类型。

      GetCollection<TDocument>(collection) 返回表示集合的 MongoCollection 对象。在本教程中,对集合调用以下方法:
  • DeleteOne – 删除与提供的搜索条件匹配的单个文档。
  • Find – 返回集合中与提供的搜索条件匹配的所有文档。
  • InsertOne – 插入提供的对象作为集合中的新文档。
  • ReplaceOne – 将与提供的搜索条件匹配的单个文档替换为提供的对象。

添加控制器Add a controller

使用以下代码将 BooksController 类添加到 Controllers 目录:

  1. using BooksApi.Models;
  2. using BooksApi.Services;
  3. using Microsoft.AspNetCore.Mvc;
  4. using System.Collections.Generic;
  5. namespace BooksApi.Controllers
  6. {
  7. [Route("api/[controller]")]
  8. [ApiController]
  9. public class BooksController : ControllerBase
  10. {
  11. private readonly BookService _bookService;
  12. public BooksController(BookService bookService)
  13. {
  14. _bookService = bookService;
  15. }
  16. [HttpGet]
  17. public ActionResult<List<Book>> Get() =>
  18. _bookService.Get();
  19. [HttpGet("{id:length(24)}", Name = "GetBook")]
  20. public ActionResult<Book> Get(string id)
  21. {
  22. var book = _bookService.Get(id);
  23. if (book == null)
  24. {
  25. return NotFound();
  26. }
  27. return book;
  28. }
  29. [HttpPost]
  30. public ActionResult<Book> Create(Book book)
  31. {
  32. _bookService.Create(book);
  33. return CreatedAtRoute("GetBook", new { id = book.Id.ToString() }, book);
  34. }
  35. [HttpPut("{id:length(24)}")]
  36. public IActionResult Update(string id, Book bookIn)
  37. {
  38. var book = _bookService.Get(id);
  39. if (book == null)
  40. {
  41. return NotFound();
  42. }
  43. _bookService.Update(id, bookIn);
  44. return NoContent();
  45. }
  46. [HttpDelete("{id:length(24)}")]
  47. public IActionResult Delete(string id)
  48. {
  49. var book = _bookService.Get(id);
  50. if (book == null)
  51. {
  52. return NotFound();
  53. }
  54. _bookService.Remove(book.Id);
  55. return NoContent();
  56. }
  57. }
  58. }

前面的 Web API 控制器:

  • 使用 BookService 类执行 CRUD 操作。
  • 包含操作方法以支持 GET、POST、PUT 和 DELETE HTTP 请求。
  • Create 操作方法中调用 CreatedAtRoute,以返回 HTTP 201 响应。状态代码 201 是在服务器上创建新资源的 HTTP POST 方法的标准响应。CreatedAtRoute 还会将 Location 标头添加到响应中。Location 标头指定新建书籍的 URI。

测试 Web APITest the web API

  1. [
  2. {
  3. "id":"5bfd996f7b8e48dc15ff215d",
  4. "bookName":"Design Patterns",
  5. "price":54.93,
  6. "category":"Computers",
  7. "author":"Ralph Johnson"
  8. },
  9. {
  10. "id":"5bfd996f7b8e48dc15ff215e",
  11. "bookName":"Clean Code",
  12. "price":43.15,
  13. "category":"Computers",
  14. "author":"Robert C. Martin"
  15. }
  16. ]
  1. {
  2. "id":"{ID}",
  3. "bookName":"Clean Code",
  4. "price":43.15,
  5. "category":"Computers",
  6. "author":"Robert C. Martin"
  7. }

配置 JSON 序列化选项Configure JSON serialization options

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

  • 应更改属性名称的默认驼峰式大小写风格,以匹配 CLR 对象属性名称的 Pascal 大小写。
  • bookName 属性应作为 Name 返回。

为满足上述要求,请进行以下更改:

  • Startup.ConfigureServices 中,将以下突出显示的代码链接到 AddMvc 方法调用:
  1. public void ConfigureServices(IServiceCollection services)
  2. {
  3. services.Configure<BookstoreDatabaseSettings>(
  4. Configuration.GetSection(nameof(BookstoreDatabaseSettings)));
  5. services.AddSingleton<IBookstoreDatabaseSettings>(sp =>
  6. sp.GetRequiredService<IOptions<BookstoreDatabaseSettings>>().Value);
  7. services.AddSingleton<BookService>();
  8. services.AddMvc()
  9. .AddJsonOptions(options => options.UseMemberCasing())
  10. .SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
  11. }

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

  • 在 Models/Book.cs 中,使用以下 [JsonProperty] 特性批注 BookName 属性 :
  1. [BsonElement("Name")]
  2. [JsonProperty("Name")]
  3. public string BookName { get; set; }

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

  • 在 Models/Book.cs 顶部添加以下代码,以解析 [JsonProperty] 属性引用 :
  1. using Newtonsoft.Json;
  • 重复测试 Web API 部分中定义的步骤。注意 JSON 属性名称中的区别。

向 Web API 添加身份验证支持Add authentication support to a web API

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

IdentityServer4 是适用于 ASP.NET Core 3.0 的 OpenID Connect 和 OAuth 2.0 框架。IdentityServer4 支持以下安全功能:

  • 身份验证即服务 (AaaS)
  • 跨多个应用程序类型的单一登录/注销 (SSO)
  • API 的访问控制
  • Federation Gateway

有关详细信息,请参阅欢迎使用 IdentityServer4

后续步骤Next steps

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