Создание веб-API с помощью ASP.NET Core и MongoDB
Примечание.
Это не последняя версия этой статьи. В текущем выпуске см . версию .NET 8 этой статьи.
Внимание
Эта информация относится к предварительному выпуску продукта, который может быть существенно изменен до его коммерческого выпуска. Майкрософт не предоставляет никаких гарантий, явных или подразумеваемых, относительно приведенных здесь сведений.
В текущем выпуске см . версию .NET 8 этой статьи.
Авторы Пратик Ханделвал (Pratik Khandelwal) и Скотт Эдди (Scott Addie).
В этом руководстве описано, как создать веб-API, который выполняет операции создания, чтения, обновления и удаления (CRUD) с базой данных NoSQL MongoDB.
В этом руководстве описано следующее:
- настроить MongoDB;
- Создание базы данных MongoDB
- определить коллекцию и схему MongoDB;
- выполнить операции CRUD MongoDB из веб-API.
- Настройка сериализации JSON
Необходимые компоненты
Visual Studio 2022 с рабочей нагрузкой ASP.NET и веб-разработка.
настроить MongoDB;
Включите доступ к Оболочке MongoDB и MongoDB из любого места на компьютере разработки (Windows/Linux/macOS):
Скачайте и установите оболочку MongoDB:
- macOS/Linux: выберите каталог для извлечения оболочки MongoDB в. Добавьте полученный путь к
mongosh
переменнойPATH
среды. - Windows: Оболочка MongoDB (mongosh.exe) устанавливается в C:\Users<\user>\AppData\Local\Programs\mongosh. Добавьте полученный путь к
mongosh.exe
переменнойPATH
среды.
- macOS/Linux: выберите каталог для извлечения оболочки MongoDB в. Добавьте полученный путь к
Скачайте и установите MongoDB:
- macOS/Linux: проверьте каталог, по которому был установлен MongoDB, обычно в /usr/local/mongodb. Добавьте полученный путь к
mongodb
переменнойPATH
среды. - Windows: MongoDB устанавливается в C:\Program Files\MongoDB по умолчанию. Добавьте C:\Program Files\MongoDB\Server\<version_number>\bin в переменную среды
PATH
.
- macOS/Linux: проверьте каталог, по которому был установлен MongoDB, обычно в /usr/local/mongodb. Добавьте полученный путь к
Выберите каталог служба хранилища данных: выберите каталог на компьютере разработки для хранения данных. Если такого каталога нет, создайте его. Оболочка MongoDB не создает новые каталоги:
- macOS/Linux: например,
/usr/local/var/mongodb
. - Windows: например,
C:\\BooksData
.
- macOS/Linux: например,
В командной оболочке ОС (а не в оболочке MongoDB) используйте следующую команду, чтобы подключиться к MongoDB через порт 27017 по умолчанию. Замените
<data_directory_path>
каталог, выбранный на предыдущем шаге.mongod --dbpath <data_directory_path>
В следующих шагах используйте ранее установленный интерфейс MongoDB, чтобы создать базу данных и коллекции и сохранить документы. Дополнительные сведения о командах MongoDB: mongosh
.
Откройте экземпляр командной оболочки MongoDB, запуская
mongosh.exe
.В командной оболочке подключитесь к тестовой базе данных по умолчанию, выполнив следующую команду:
mongosh
Выполните приведенную ниже команду в командной оболочке.
use BookStore
Будет создана база данных с именем BookStore, если она не существует. Если такая база данных существует, для нее уже установлено подключение для транзакций.
Создайте коллекцию
Books
с помощью такой команды:db.createCollection('Books')
Отобразится такой результат:
{ "ok" : 1 }
Определите схему для коллекции
Books
и вставьте два документа, используя следующую команду:db.Books.insertMany([{ "Name": "Design Patterns", "Price": 54.93, "Category": "Computers", "Author": "Ralph Johnson" }, { "Name": "Clean Code", "Price": 43.15, "Category": "Computers","Author": "Robert C. Martin" }])
Отобразится примерно такой результат:
{ "acknowledged" : true, "insertedIds" : [ ObjectId("61a6058e6c43f32854e51f51"), ObjectId("61a6058e6c43f32854e51f52") ] }
Примечание.
Приведенные
ObjectId
выше результаты не соответствуют приведенным в командной оболочке.Просмотрите документы в базе данных, используя такую команду:
db.Books.find().pretty()
Отобразится примерно такой результат:
{ "_id" : ObjectId("61a6058e6c43f32854e51f51"), "Name" : "Design Patterns", "Price" : 54.93, "Category" : "Computers", "Author" : "Ralph Johnson" } { "_id" : ObjectId("61a6058e6c43f32854e51f52"), "Name" : "Clean Code", "Price" : 43.15, "Category" : "Computers", "Author" : "Robert C. Martin" }
Схема добавляет автоматически созданное свойство
_id
типаObjectId
к каждому документу.
Создание проекта веб-API ASP.NET Core
Выберите Файл>Создать>Проект.
Выберите тип проекта Веб-API ASP.NET Core и щелкните Далее.
Назовите проект BookStoreApi и щелкните Создать.
Выберите платформу .NET 8.0 (долгосрочная поддержка) и нажмите кнопку "Создать".
В окне Консоль диспетчера пакетов перейдите в корневую папку проекта. Выполните следующую команду, чтобы установить драйвер .NET для MongoDB:
Install-Package MongoDB.Driver
Добавление модели сущности
Добавьте каталог Models в корневую папку проекта.
Добавьте класс
Book
в каталог Models с помощью такого кода:using MongoDB.Bson; using MongoDB.Bson.Serialization.Attributes; namespace BookStoreApi.Models; public class Book { [BsonId] [BsonRepresentation(BsonType.ObjectId)] public string? Id { get; set; } [BsonElement("Name")] public string BookName { get; set; } = null!; public decimal Price { get; set; } public string Category { get; set; } = null!; public string Author { get; set; } = null!; }
В классе выше свойство
Id
:- Требуется для сопоставления объекта среды CLR с коллекцией MongoDB.
- Помечается с помощью
[BsonId]
для назначения этого свойства в качестве первичного ключа документа. - Помечается с помощью
[BsonRepresentation(BsonType.ObjectId)]
, чтобы разрешить передачу параметра в качестве типаstring
вместо структуры ObjectId. Mongo обрабатывает преобразование изstring
вObjectId
.
Свойство
BookName
помечено атрибутом[BsonElement]
. Значение атрибутаName
представляет имя свойства в коллекции MongoDB.
Добавление модели конфигурации
Добавьте в файл
appsettings.json
следующие значения конфигурации базы данных:{ "BookStoreDatabase": { "ConnectionString": "mongodb://localhost:27017", "DatabaseName": "BookStore", "BooksCollectionName": "Books" }, "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Warning" } }, "AllowedHosts": "*" }
Добавьте класс
BookStoreDatabaseSettings
в каталог Models с помощью такого кода:namespace BookStoreApi.Models; public class BookStoreDatabaseSettings { public string ConnectionString { get; set; } = null!; public string DatabaseName { get; set; } = null!; public string BooksCollectionName { get; set; } = null!; }
Предыдущий класс
BookStoreDatabaseSettings
используется для хранения значений свойствBookStoreDatabase
файлаappsettings.json
. Свойства JSON и C# имеют одинаковые имена, что упрощает сопоставление.Добавьте выделенный ниже код в
Program.cs
:var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.Configure<BookStoreDatabaseSettings>( builder.Configuration.GetSection("BookStoreDatabase"));
В предыдущем коде экземпляр конфигурации, к которому привязан раздел
BookStoreDatabase
файлаappsettings.json
, зарегистрирован в контейнере внедрения зависимостей (DI). Например, свойствоConnectionString
объектаBookStoreDatabaseSettings
заполняется свойствомBookStoreDatabase:ConnectionString
вappsettings.json
.Добавьте следующий код в самое начало файла
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); }
В предыдущем коде экземпляр
BookStoreDatabaseSettings
извлекается из DI путем внедрения конструктора. Таким образом обеспечивается доступ к значениям конфигурации в файлеappsettings.json
, которые были добавлены в разделе Добавление модели конфигурации.Добавьте выделенный ниже код в
Program.cs
:var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.Configure<BookStoreDatabaseSettings>( builder.Configuration.GetSection("BookStoreDatabase")); builder.Services.AddSingleton<BooksService>();
В предыдущем коде класс
BooksService
регистрируется в DI, чтобы обеспечить поддержку внедрения через конструктор в используемые классы. Время существования отдельной службы — наиболее подходящий вариант, так какBooksService
имеет прямую зависимость отMongoClient
. В соответствии с официальными правилами повторного использования клиента MongoMongoClient
следует регистрировать в 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 для выполнения операций. В этом руководстве используется универсальный метод GetCollection<TDocument>(collection) интерфейса для получения доступа к данным в определенной коллекции. Выполняйте операции CRUD с коллекцией после вызова этого метода. В вызове метода
GetCollection<TDocument>(collection)
:collection
представляет имя коллекции;TDocument
представляет тип объекта среды CLR, хранящегося в коллекции;
GetCollection<TDocument>(collection)
возвращает объект MongoCollection, представляющий коллекцию. В этом руководстве следующие методы вызываются для коллекции:
- DeleteOne — удаляет один документ, отвечающий заданным критериям поиска.
- Find<TDocument> — возвращает все документы в коллекции, соответствующие заданным критериям поиска.
- InsertOneAsync — вставляет предоставленный объект в виде нового документа в коллекции.
- ReplaceOneAsync — заменяет один документ, отвечающий заданным критериям поиска, предоставленным объектом.
Добавление контроллера
Добавьте класс BooksController
в каталог Controllers с помощью такого кода:
using BookStoreApi.Models;
using BookStoreApi.Services;
using Microsoft.AspNetCore.Mvc;
namespace BookStoreApi.Controllers;
[ApiController]
[Route("api/[controller]")]
public class BooksController : ControllerBase
{
private readonly BooksService _booksService;
public BooksController(BooksService booksService) =>
_booksService = booksService;
[HttpGet]
public async Task<List<Book>> Get() =>
await _booksService.GetAsync();
[HttpGet("{id:length(24)}")]
public async Task<ActionResult<Book>> Get(string id)
{
var book = await _booksService.GetAsync(id);
if (book is null)
{
return NotFound();
}
return book;
}
[HttpPost]
public async Task<IActionResult> Post(Book newBook)
{
await _booksService.CreateAsync(newBook);
return CreatedAtAction(nameof(Get), new { id = newBook.Id }, newBook);
}
[HttpPut("{id:length(24)}")]
public async Task<IActionResult> Update(string id, Book updatedBook)
{
var book = await _booksService.GetAsync(id);
if (book is null)
{
return NotFound();
}
updatedBook.Id = book.Id;
await _booksService.UpdateAsync(id, updatedBook);
return NoContent();
}
[HttpDelete("{id:length(24)}")]
public async Task<IActionResult> Delete(string id)
{
var book = await _booksService.GetAsync(id);
if (book is null)
{
return NotFound();
}
await _booksService.RemoveAsync(id);
return NoContent();
}
}
Предыдущий контроллер веб-API:
- использует класс
BooksService
для выполнения операций CRUD; - содержит методы действий для поддержки запросов HTTP GET, POST, PUT и DELETE.
- Вызывает CreatedAtAction в методе действия
Create
для возврата ответа HTTP 201. Код состояния 201 представляет собой стандартный ответ метода HTTP POST, создающего ресурс на сервере.CreatedAtAction
также добавляет заголовокLocation
в ответ. ЗаголовокLocation
указывает универсальный код ресурса (URI) созданной книги.
Тестирование веб-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
Нужно изменить два параметра для возвращаемых ответов JSON в разделе Тестирование веб-API:
- Смешанный регистр имен свойств по умолчанию следует изменить в соответствии с регистром Pascal имен свойств объекта CLR.
- Свойство
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);
После предыдущего изменения имена свойств в ответе сериализованного JSON веб-API соответствуют именам свойств в типе объекта CLR. Например, свойство
Author
классаBook
сериализуется какAuthor
, а неauthor
.В
Models/Book.cs
добавьте к свойствуBookName
атрибут[JsonPropertyName]
:[BsonElement("Name")] [JsonPropertyName("Name")] public string BookName { get; set; } = null!;
Атрибут
[JsonPropertyName]
со значениемName
представляет имя свойства в сериализованном ответе веб-API в формате JSON.Добавьте следующий код в самое начало файла
Models/Book.cs
, чтобы разрешить ссылку на атрибут[JsonProperty]
:using System.Text.Json.Serialization;
Повторите действия, описанные в разделе Тестирование веб-API. Обратите внимание на различие в именах свойств JSON.
Добавление поддержки аутентификации в веб-API
ASP.NET Core Identity позволяет использовать функцию входа в пользовательском интерфейсе для веб-приложений ASP.NET Core. Чтобы защитить веб-API и одностраничные приложения, используйте один из следующих способов:
- Microsoft Entra ID
- Azure Active Directory B2C (Azure AD B2C)
- Duende Identity Server
Duende Identity Server — это платформа OpenID Connect и OAuth 2.0 для ASP.NET Core. Duende Identity Server включает следующие функции безопасности:
- Проверка подлинности как услуга (AaaS)
- Единый вход (SSO) для нескольких типов приложений
- Контроль доступа для API
- Шлюз федерации
Внимание
Компания Duende Software может потребовать лицензионный сбор за использование Duende IdentityServer в рабочей среде. Дополнительные сведения см. в статье Миграция с ASP.NET Core 5.0 на 6.0.
Дополнительные сведения см. в документации по Duende Identity Server (на веб-сайте ПО Duende).
Дополнительные ресурсы
В этом руководстве описано, как создать веб-API, который выполняет операции создания, чтения, обновления и удаления (CRUD) с базой данных NoSQL MongoDB.
В этом руководстве описано следующее:
- настроить MongoDB;
- Создание базы данных MongoDB
- определить коллекцию и схему MongoDB;
- выполнить операции CRUD MongoDB из веб-API.
- Настройка сериализации JSON
Необходимые компоненты
Visual Studio 2022 с рабочей нагрузкой ASP.NET и веб-разработка.
настроить MongoDB;
Включите доступ к оболочке MongoDB и Mongo DB из любого места на компьютере разработки:
В Windows MongoDB по умолчанию устанавливается в папку C:\Program Files\MongoDB. Добавьте C:\Program Files\MongoDB\Server\<version_number>\bin в переменную среды
PATH
.Скачайте оболочку MongoDB и выберите каталог, чтобы извлечь его. Добавьте полученный путь к
mongosh.exe
переменнойPATH
среды.Выберите каталог на компьютере разработки для хранения данных. Например C:\BooksData при работе в Windows. Если такого каталога нет, создайте его. В mongo Shell нельзя создавать каталоги.
В командной оболочке ОС (а не в оболочке MongoDB) используйте следующую команду, чтобы подключиться к MongoDB через порт 27017 по умолчанию. Замените
<data_directory_path>
каталог, выбранный на предыдущем шаге.mongod --dbpath <data_directory_path>
В следующих шагах используйте ранее установленный интерфейс MongoDB, чтобы создать базу данных и коллекции и сохранить документы. Дополнительные сведения о командах MongoDB: mongosh
.
Откройте экземпляр командной оболочки MongoDB, запуская
mongosh.exe
.В командной оболочке подключитесь к тестовой базе данных по умолчанию, выполнив следующую команду:
mongosh
Выполните приведенную ниже команду в командной оболочке.
use BookStore
Будет создана база данных с именем BookStore, если она не существует. Если такая база данных существует, для нее уже установлено подключение для транзакций.
Создайте коллекцию
Books
с помощью такой команды:db.createCollection('Books')
Отобразится такой результат:
{ "ok" : 1 }
Определите схему для коллекции
Books
и вставьте два документа, используя следующую команду:db.Books.insertMany([{ "Name": "Design Patterns", "Price": 54.93, "Category": "Computers", "Author": "Ralph Johnson" }, { "Name": "Clean Code", "Price": 43.15, "Category": "Computers","Author": "Robert C. Martin" }])
Отобразится примерно такой результат:
{ "acknowledged" : true, "insertedIds" : [ ObjectId("61a6058e6c43f32854e51f51"), ObjectId("61a6058e6c43f32854e51f52") ] }
Примечание.
Приведенные
ObjectId
выше результаты не соответствуют приведенным в командной оболочке.Просмотрите документы в базе данных, используя такую команду:
db.Books.find().pretty()
Отобразится примерно такой результат:
{ "_id" : ObjectId("61a6058e6c43f32854e51f51"), "Name" : "Design Patterns", "Price" : 54.93, "Category" : "Computers", "Author" : "Ralph Johnson" } { "_id" : ObjectId("61a6058e6c43f32854e51f52"), "Name" : "Clean Code", "Price" : 43.15, "Category" : "Computers", "Author" : "Robert C. Martin" }
Схема добавляет автоматически созданное свойство
_id
типаObjectId
к каждому документу.
Создание проекта веб-API ASP.NET Core
Выберите Файл>Создать>Проект.
Выберите тип проекта Веб-API ASP.NET Core и щелкните Далее.
Назовите проект BookStoreApi и щелкните Создать.
Выберите платформу .NET 7.0 (стандартная поддержка терминов) и нажмите кнопку "Создать".
В меню Сервис последовательно выберите пункты Диспетчер пакетов NuGet>Консоль диспетчера пакетов.
В окне Консоль диспетчера пакетов перейдите в корневую папку проекта. Выполните следующую команду, чтобы установить драйвер .NET для MongoDB:
Install-Package MongoDB.Driver
Добавление модели сущности
Добавьте каталог Models в корневую папку проекта.
Добавьте класс
Book
в каталог Models с помощью такого кода:using MongoDB.Bson; using MongoDB.Bson.Serialization.Attributes; namespace BookStoreApi.Models; public class Book { [BsonId] [BsonRepresentation(BsonType.ObjectId)] public string? Id { get; set; } [BsonElement("Name")] public string BookName { get; set; } = null!; public decimal Price { get; set; } public string Category { get; set; } = null!; public string Author { get; set; } = null!; }
В классе выше свойство
Id
:- Требуется для сопоставления объекта среды CLR с коллекцией MongoDB.
- Помечается с помощью
[BsonId]
для назначения этого свойства в качестве первичного ключа документа. - Помечается с помощью
[BsonRepresentation(BsonType.ObjectId)]
, чтобы разрешить передачу параметра в качестве типаstring
вместо структуры ObjectId. Mongo обрабатывает преобразование изstring
вObjectId
.
Свойство
BookName
помечено атрибутом[BsonElement]
. Значение атрибутаName
представляет имя свойства в коллекции MongoDB.
Добавление модели конфигурации
Добавьте в файл
appsettings.json
следующие значения конфигурации базы данных:{ "BookStoreDatabase": { "ConnectionString": "mongodb://localhost:27017", "DatabaseName": "BookStore", "BooksCollectionName": "Books" }, "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Warning" } }, "AllowedHosts": "*" }
Добавьте класс
BookStoreDatabaseSettings
в каталог Models с помощью такого кода:namespace BookStoreApi.Models; public class BookStoreDatabaseSettings { public string ConnectionString { get; set; } = null!; public string DatabaseName { get; set; } = null!; public string BooksCollectionName { get; set; } = null!; }
Предыдущий класс
BookStoreDatabaseSettings
используется для хранения значений свойствBookStoreDatabase
файлаappsettings.json
. Свойства JSON и C# имеют одинаковые имена, что упрощает сопоставление.Добавьте выделенный ниже код в
Program.cs
:var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.Configure<BookStoreDatabaseSettings>( builder.Configuration.GetSection("BookStoreDatabase"));
В предыдущем коде экземпляр конфигурации, к которому привязан раздел
BookStoreDatabase
файлаappsettings.json
, зарегистрирован в контейнере внедрения зависимостей (DI). Например, свойствоConnectionString
объектаBookStoreDatabaseSettings
заполняется свойствомBookStoreDatabase:ConnectionString
вappsettings.json
.Добавьте следующий код в самое начало файла
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); }
В предыдущем коде экземпляр
BookStoreDatabaseSettings
извлекается из DI путем внедрения конструктора. Таким образом обеспечивается доступ к значениям конфигурации в файлеappsettings.json
, которые были добавлены в разделе Добавление модели конфигурации.Добавьте выделенный ниже код в
Program.cs
:var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.Configure<BookStoreDatabaseSettings>( builder.Configuration.GetSection("BookStoreDatabase")); builder.Services.AddSingleton<BooksService>();
В предыдущем коде класс
BooksService
регистрируется в DI, чтобы обеспечить поддержку внедрения через конструктор в используемые классы. Время существования отдельной службы — наиболее подходящий вариант, так какBooksService
имеет прямую зависимость отMongoClient
. В соответствии с официальными правилами повторного использования клиента MongoMongoClient
следует регистрировать в 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 для выполнения операций. В этом руководстве используется универсальный метод GetCollection<TDocument>(collection) интерфейса для получения доступа к данным в определенной коллекции. Выполняйте операции CRUD с коллекцией после вызова этого метода. В вызове метода
GetCollection<TDocument>(collection)
:collection
представляет имя коллекции;TDocument
представляет тип объекта среды CLR, хранящегося в коллекции;
GetCollection<TDocument>(collection)
возвращает объект MongoCollection, представляющий коллекцию. В этом руководстве следующие методы вызываются для коллекции:
- DeleteOne — удаляет один документ, отвечающий заданным критериям поиска.
- Find<TDocument> — возвращает все документы в коллекции, соответствующие заданным критериям поиска.
- InsertOneAsync — вставляет предоставленный объект в виде нового документа в коллекции.
- ReplaceOneAsync — заменяет один документ, отвечающий заданным критериям поиска, предоставленным объектом.
Добавление контроллера
Добавьте класс BooksController
в каталог Controllers с помощью такого кода:
using BookStoreApi.Models;
using BookStoreApi.Services;
using Microsoft.AspNetCore.Mvc;
namespace BookStoreApi.Controllers;
[ApiController]
[Route("api/[controller]")]
public class BooksController : ControllerBase
{
private readonly BooksService _booksService;
public BooksController(BooksService booksService) =>
_booksService = booksService;
[HttpGet]
public async Task<List<Book>> Get() =>
await _booksService.GetAsync();
[HttpGet("{id:length(24)}")]
public async Task<ActionResult<Book>> Get(string id)
{
var book = await _booksService.GetAsync(id);
if (book is null)
{
return NotFound();
}
return book;
}
[HttpPost]
public async Task<IActionResult> Post(Book newBook)
{
await _booksService.CreateAsync(newBook);
return CreatedAtAction(nameof(Get), new { id = newBook.Id }, newBook);
}
[HttpPut("{id:length(24)}")]
public async Task<IActionResult> Update(string id, Book updatedBook)
{
var book = await _booksService.GetAsync(id);
if (book is null)
{
return NotFound();
}
updatedBook.Id = book.Id;
await _booksService.UpdateAsync(id, updatedBook);
return NoContent();
}
[HttpDelete("{id:length(24)}")]
public async Task<IActionResult> Delete(string id)
{
var book = await _booksService.GetAsync(id);
if (book is null)
{
return NotFound();
}
await _booksService.RemoveAsync(id);
return NoContent();
}
}
Предыдущий контроллер веб-API:
- использует класс
BooksService
для выполнения операций CRUD; - содержит методы действий для поддержки запросов HTTP GET, POST, PUT и DELETE.
- Вызывает CreatedAtAction в методе действия
Create
для возврата ответа HTTP 201. Код состояния 201 представляет собой стандартный ответ метода HTTP POST, создающего ресурс на сервере.CreatedAtAction
также добавляет заголовокLocation
в ответ. ЗаголовокLocation
указывает универсальный код ресурса (URI) созданной книги.
Тестирование веб-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
Нужно изменить два параметра для возвращаемых ответов JSON в разделе Тестирование веб-API:
- Смешанный регистр имен свойств по умолчанию следует изменить в соответствии с регистром Pascal имен свойств объекта CLR.
- Свойство
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);
После предыдущего изменения имена свойств в ответе сериализованного JSON веб-API соответствуют именам свойств в типе объекта CLR. Например, свойство
Author
классаBook
сериализуется какAuthor
, а неauthor
.В
Models/Book.cs
добавьте к свойствуBookName
атрибут[JsonPropertyName]
:[BsonElement("Name")] [JsonPropertyName("Name")] public string BookName { get; set; } = null!;
Атрибут
[JsonPropertyName]
со значениемName
представляет имя свойства в сериализованном ответе веб-API в формате JSON.Добавьте следующий код в самое начало файла
Models/Book.cs
, чтобы разрешить ссылку на атрибут[JsonProperty]
:using System.Text.Json.Serialization;
Повторите действия, описанные в разделе Тестирование веб-API. Обратите внимание на различие в именах свойств JSON.
Добавление поддержки аутентификации в веб-API
ASP.NET Core Identity позволяет использовать функцию входа в пользовательском интерфейсе для веб-приложений ASP.NET Core. Чтобы защитить веб-API и одностраничные приложения, используйте один из следующих способов:
- Microsoft Entra ID
- Azure Active Directory B2C (Azure AD B2C)
- Duende Identity Server
Duende Identity Server — это платформа OpenID Connect и OAuth 2.0 для ASP.NET Core. Duende Identity Server включает следующие функции безопасности:
- Проверка подлинности как услуга (AaaS)
- Единый вход (SSO) для нескольких типов приложений
- Контроль доступа для API
- Шлюз федерации
Внимание
Компания Duende Software может потребовать лицензионный сбор за использование Duende IdentityServer в рабочей среде. Дополнительные сведения см. в статье Миграция с ASP.NET Core 5.0 на 6.0.
Дополнительные сведения см. в документации по Duende Identity Server (на веб-сайте ПО Duende).
Дополнительные ресурсы
В этом руководстве описано, как создать веб-API, который выполняет операции создания, чтения, обновления и удаления (CRUD) с базой данных NoSQL MongoDB.
В этом руководстве описано следующее:
- настроить MongoDB;
- Создание базы данных MongoDB
- определить коллекцию и схему MongoDB;
- выполнить операции CRUD MongoDB из веб-API.
- Настройка сериализации JSON
Необходимые компоненты
- Visual Studio 2022 с рабочей нагрузкой ASP.NET и веб-разработка.
- Пакет SDK для .NET 6.0
настроить MongoDB;
Включите доступ к оболочке MongoDB и Mongo DB из любого места на компьютере разработки:
В Windows MongoDB по умолчанию устанавливается в папку C:\Program Files\MongoDB. Добавьте C:\Program Files\MongoDB\Server\<version_number>\bin в переменную среды
PATH
.Скачайте оболочку MongoDB и выберите каталог, чтобы извлечь его. Добавьте полученный путь к
mongosh.exe
переменнойPATH
среды.Выберите каталог на компьютере разработки для хранения данных. Например C:\BooksData при работе в Windows. Если такого каталога нет, создайте его. В mongo Shell нельзя создавать каталоги.
В командной оболочке ОС (а не в оболочке MongoDB) используйте следующую команду, чтобы подключиться к MongoDB через порт 27017 по умолчанию. Замените
<data_directory_path>
каталог, выбранный на предыдущем шаге.mongod --dbpath <data_directory_path>
В следующих шагах используйте ранее установленный интерфейс MongoDB, чтобы создать базу данных и коллекции и сохранить документы. Дополнительные сведения о командах MongoDB: mongosh
.
Откройте экземпляр командной оболочки MongoDB, запуская
mongosh.exe
.В командной оболочке подключитесь к тестовой базе данных по умолчанию, выполнив следующую команду:
mongosh
Выполните приведенную ниже команду в командной оболочке.
use BookStore
Будет создана база данных с именем BookStore, если она не существует. Если такая база данных существует, для нее уже установлено подключение для транзакций.
Создайте коллекцию
Books
с помощью такой команды:db.createCollection('Books')
Отобразится такой результат:
{ "ok" : 1 }
Определите схему для коллекции
Books
и вставьте два документа, используя следующую команду:db.Books.insertMany([{ "Name": "Design Patterns", "Price": 54.93, "Category": "Computers", "Author": "Ralph Johnson" }, { "Name": "Clean Code", "Price": 43.15, "Category": "Computers","Author": "Robert C. Martin" }])
Отобразится примерно такой результат:
{ "acknowledged" : true, "insertedIds" : [ ObjectId("61a6058e6c43f32854e51f51"), ObjectId("61a6058e6c43f32854e51f52") ] }
Примечание.
Приведенные
ObjectId
выше результаты не соответствуют приведенным в командной оболочке.Просмотрите документы в базе данных, используя такую команду:
db.Books.find().pretty()
Отобразится примерно такой результат:
{ "_id" : ObjectId("61a6058e6c43f32854e51f51"), "Name" : "Design Patterns", "Price" : 54.93, "Category" : "Computers", "Author" : "Ralph Johnson" } { "_id" : ObjectId("61a6058e6c43f32854e51f52"), "Name" : "Clean Code", "Price" : 43.15, "Category" : "Computers", "Author" : "Robert C. Martin" }
Схема добавляет автоматически созданное свойство
_id
типаObjectId
к каждому документу.
Создание проекта веб-API ASP.NET Core
Выберите Файл>Создать>Проект.
Выберите тип проекта Веб-API ASP.NET Core и щелкните Далее.
Назовите проект BookStoreApi и щелкните Создать.
Выберите платформу .NET 6.0 (долгосрочная поддержка) и щелкните Создать.
В окне Консоль диспетчера пакетов перейдите в корневую папку проекта. Выполните следующую команду, чтобы установить драйвер .NET для MongoDB:
Install-Package MongoDB.Driver
Добавление модели сущности
Добавьте каталог Models в корневую папку проекта.
Добавьте класс
Book
в каталог Models с помощью такого кода:using MongoDB.Bson; using MongoDB.Bson.Serialization.Attributes; namespace BookStoreApi.Models; public class Book { [BsonId] [BsonRepresentation(BsonType.ObjectId)] public string? Id { get; set; } [BsonElement("Name")] public string BookName { get; set; } = null!; public decimal Price { get; set; } public string Category { get; set; } = null!; public string Author { get; set; } = null!; }
В классе выше свойство
Id
:- Требуется для сопоставления объекта среды CLR с коллекцией MongoDB.
- Помечается с помощью
[BsonId]
для назначения этого свойства в качестве первичного ключа документа. - Помечается с помощью
[BsonRepresentation(BsonType.ObjectId)]
, чтобы разрешить передачу параметра в качестве типаstring
вместо структуры ObjectId. Mongo обрабатывает преобразование изstring
вObjectId
.
Свойство
BookName
помечено атрибутом[BsonElement]
. Значение атрибутаName
представляет имя свойства в коллекции MongoDB.
Добавление модели конфигурации
Добавьте в файл
appsettings.json
следующие значения конфигурации базы данных:{ "BookStoreDatabase": { "ConnectionString": "mongodb://localhost:27017", "DatabaseName": "BookStore", "BooksCollectionName": "Books" }, "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Warning" } }, "AllowedHosts": "*" }
Добавьте класс
BookStoreDatabaseSettings
в каталог Models с помощью такого кода:namespace BookStoreApi.Models; public class BookStoreDatabaseSettings { public string ConnectionString { get; set; } = null!; public string DatabaseName { get; set; } = null!; public string BooksCollectionName { get; set; } = null!; }
Предыдущий класс
BookStoreDatabaseSettings
используется для хранения значений свойствBookStoreDatabase
файлаappsettings.json
. Свойства JSON и C# имеют одинаковые имена, что упрощает сопоставление.Добавьте выделенный ниже код в
Program.cs
:var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.Configure<BookStoreDatabaseSettings>( builder.Configuration.GetSection("BookStoreDatabase"));
В предыдущем коде экземпляр конфигурации, к которому привязан раздел
BookStoreDatabase
файлаappsettings.json
, зарегистрирован в контейнере внедрения зависимостей (DI). Например, свойствоConnectionString
объектаBookStoreDatabaseSettings
заполняется свойствомBookStoreDatabase:ConnectionString
вappsettings.json
.Добавьте следующий код в самое начало файла
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); }
В предыдущем коде экземпляр
BookStoreDatabaseSettings
извлекается из DI путем внедрения конструктора. Таким образом обеспечивается доступ к значениям конфигурации в файлеappsettings.json
, которые были добавлены в разделе Добавление модели конфигурации.Добавьте выделенный ниже код в
Program.cs
:var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.Configure<BookStoreDatabaseSettings>( builder.Configuration.GetSection("BookStoreDatabase")); builder.Services.AddSingleton<BooksService>();
В предыдущем коде класс
BooksService
регистрируется в DI, чтобы обеспечить поддержку внедрения через конструктор в используемые классы. Время существования отдельной службы — наиболее подходящий вариант, так какBooksService
имеет прямую зависимость отMongoClient
. В соответствии с официальными правилами повторного использования клиента MongoMongoClient
следует регистрировать в 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 для выполнения операций. В этом руководстве используется универсальный метод GetCollection<TDocument>(collection) интерфейса для получения доступа к данным в определенной коллекции. Выполняйте операции CRUD с коллекцией после вызова этого метода. В вызове метода
GetCollection<TDocument>(collection)
:collection
представляет имя коллекции;TDocument
представляет тип объекта среды CLR, хранящегося в коллекции;
GetCollection<TDocument>(collection)
возвращает объект MongoCollection, представляющий коллекцию. В этом руководстве следующие методы вызываются для коллекции:
- DeleteOne — удаляет один документ, отвечающий заданным критериям поиска.
- Find<TDocument> — возвращает все документы в коллекции, соответствующие заданным критериям поиска.
- InsertOneAsync — вставляет предоставленный объект в виде нового документа в коллекции.
- ReplaceOneAsync — заменяет один документ, отвечающий заданным критериям поиска, предоставленным объектом.
Добавление контроллера
Добавьте класс BooksController
в каталог Controllers с помощью такого кода:
using BookStoreApi.Models;
using BookStoreApi.Services;
using Microsoft.AspNetCore.Mvc;
namespace BookStoreApi.Controllers;
[ApiController]
[Route("api/[controller]")]
public class BooksController : ControllerBase
{
private readonly BooksService _booksService;
public BooksController(BooksService booksService) =>
_booksService = booksService;
[HttpGet]
public async Task<List<Book>> Get() =>
await _booksService.GetAsync();
[HttpGet("{id:length(24)}")]
public async Task<ActionResult<Book>> Get(string id)
{
var book = await _booksService.GetAsync(id);
if (book is null)
{
return NotFound();
}
return book;
}
[HttpPost]
public async Task<IActionResult> Post(Book newBook)
{
await _booksService.CreateAsync(newBook);
return CreatedAtAction(nameof(Get), new { id = newBook.Id }, newBook);
}
[HttpPut("{id:length(24)}")]
public async Task<IActionResult> Update(string id, Book updatedBook)
{
var book = await _booksService.GetAsync(id);
if (book is null)
{
return NotFound();
}
updatedBook.Id = book.Id;
await _booksService.UpdateAsync(id, updatedBook);
return NoContent();
}
[HttpDelete("{id:length(24)}")]
public async Task<IActionResult> Delete(string id)
{
var book = await _booksService.GetAsync(id);
if (book is null)
{
return NotFound();
}
await _booksService.RemoveAsync(id);
return NoContent();
}
}
Предыдущий контроллер веб-API:
- использует класс
BooksService
для выполнения операций CRUD; - содержит методы действий для поддержки запросов HTTP GET, POST, PUT и DELETE.
- Вызывает CreatedAtAction в методе действия
Create
для возврата ответа HTTP 201. Код состояния 201 представляет собой стандартный ответ метода HTTP POST, создающего ресурс на сервере.CreatedAtAction
также добавляет заголовокLocation
в ответ. ЗаголовокLocation
указывает универсальный код ресурса (URI) созданной книги.
Тестирование веб-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
Нужно изменить два параметра для возвращаемых ответов JSON в разделе Тестирование веб-API:
- Смешанный регистр имен свойств по умолчанию следует изменить в соответствии с регистром Pascal имен свойств объекта CLR.
- Свойство
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);
После предыдущего изменения имена свойств в ответе сериализованного JSON веб-API соответствуют именам свойств в типе объекта CLR. Например, свойство
Author
классаBook
сериализуется какAuthor
, а неauthor
.В
Models/Book.cs
добавьте к свойствуBookName
атрибут[JsonPropertyName]
:[BsonElement("Name")] [JsonPropertyName("Name")] public string BookName { get; set; } = null!;
Атрибут
[JsonPropertyName]
со значениемName
представляет имя свойства в сериализованном ответе веб-API в формате JSON.Добавьте следующий код в самое начало файла
Models/Book.cs
, чтобы разрешить ссылку на атрибут[JsonProperty]
:using System.Text.Json.Serialization;
Повторите действия, описанные в разделе Тестирование веб-API. Обратите внимание на различие в именах свойств JSON.
Добавление поддержки аутентификации в веб-API
ASP.NET Core Identity позволяет использовать функцию входа в пользовательском интерфейсе для веб-приложений ASP.NET Core. Чтобы защитить веб-API и одностраничные приложения, используйте один из следующих способов:
- Microsoft Entra ID
- Azure Active Directory B2C (Azure AD B2C)
- Duende Identity Server
Duende Identity Server — это платформа OpenID Connect и OAuth 2.0 для ASP.NET Core. Duende Identity Server включает следующие функции безопасности:
- Проверка подлинности как услуга (AaaS)
- Единый вход (SSO) для нескольких типов приложений
- Контроль доступа для API
- Шлюз федерации
Внимание
Компания Duende Software может потребовать лицензионный сбор за использование Duende IdentityServer в рабочей среде. Дополнительные сведения см. в статье Миграция с ASP.NET Core 5.0 на 6.0.
Дополнительные сведения см. в документации по Duende Identity Server (на веб-сайте ПО Duende).
Дополнительные ресурсы
В этом руководстве описано, как создать веб-API, который выполняет операции создания, чтения, обновления и удаления (CRUD) с базой данных NoSQL MongoDB.
В этом руководстве описано следующее:
- настроить MongoDB;
- Создание базы данных MongoDB
- определить коллекцию и схему MongoDB;
- выполнить операции CRUD MongoDB из веб-API.
- Настройка сериализации JSON
Просмотреть или скачать образец кода (описание загрузки)
Необходимые компоненты
- Пакет SDK для .NET Core 3.0 или более поздней версии
- Visual Studio 2019 с рабочей нагрузкой ASP.NET и веб-разработка.
- MongoDB
настроить MongoDB;
Если используется Windows, MongoDB по умолчанию устанавливается в папку C:\Program Files\MongoDB. Добавьте C:\Program Files\MongoDB\Server\<version_number>\bin в переменную среды Path
. Это изменение обеспечит доступ к MongoDB из любого места на компьютере разработки.
В следующих шагах используйте интерфейс mongo Shell, чтобы создать базу данных и коллекции и сохранить документы. Дополнительные сведения о командах mongo Shell см. в руководстве по работе с mongo Shell.
Выберите папку на компьютере разработки для хранения данных. Например C:\BooksData при работе в Windows. Если такого каталога нет, создайте его. В mongo Shell нельзя создавать каталоги.
Откройте командную оболочку. Выполните следующую команду для подключения к MongoDB через порт 27017, заданный по умолчанию. Не забудьте заменить
<data_directory_path>
каталогом, созданным на предыдущем этапе.mongod --dbpath <data_directory_path>
Откройте другой экземпляр командной оболочки. Подключитесь к тестовой базе данных по умолчанию, выполнив такую команду:
mongo
В командной оболочке выполните следующую команду:
use BookstoreDb
Будет создана база данных с именем BookstoreDb, если она не существует. Если такая база данных существует, для нее уже установлено подключение для транзакций.
Создайте коллекцию
Books
с помощью такой команды:db.createCollection('Books')
Отобразится такой результат:
{ "ok" : 1 }
Определите схему для коллекции
Books
и вставьте два документа, используя следующую команду:db.Books.insertMany([{'Name':'Design Patterns','Price':54.93,'Category':'Computers','Author':'Ralph Johnson'}, {'Name':'Clean Code','Price':43.15,'Category':'Computers','Author':'Robert C. Martin'}])
Отобразится такой результат:
{ "acknowledged" : true, "insertedIds" : [ ObjectId("5bfd996f7b8e48dc15ff215d"), ObjectId("5bfd996f7b8e48dc15ff215e") ] }
Примечание.
Идентификаторы в этой статье не будут соответствовать идентификаторам в запущенном примере.
Просмотрите документы в базе данных, используя такую команду:
db.Books.find({}).pretty()
Отобразится такой результат:
{ "_id" : ObjectId("5bfd996f7b8e48dc15ff215d"), "Name" : "Design Patterns", "Price" : 54.93, "Category" : "Computers", "Author" : "Ralph Johnson" } { "_id" : ObjectId("5bfd996f7b8e48dc15ff215e"), "Name" : "Clean Code", "Price" : 43.15, "Category" : "Computers", "Author" : "Robert C. Martin" }
Схема добавляет автоматически созданное свойство
_id
типаObjectId
к каждому документу.
База данных готова к работе. Можно приступить к созданию веб-API ASP.NET Core.
Создание проекта веб-API ASP.NET Core
Выберите Файл>Создать>Проект.
Выберите тип проекта Веб-приложение ASP.NET Core и нажмите кнопку Далее.
Задайте для проекта имя BooksApi и нажмите кнопку Создать.
Выберите целевую платформу .NET Core и ASP.NET Core 3.0. Выберите шаблон проекта API и нажмите кнопку Создать.
Посетите коллекцию NuGet: MongoDB.Driver, чтобы определить последнюю стабильную версию драйвера .NET для MongoDB. В окне Консоль диспетчера пакетов перейдите в корневую папку проекта. Выполните следующую команду, чтобы установить драйвер .NET для MongoDB:
Install-Package MongoDB.Driver -Version {VERSION}
Добавление модели сущности
Добавьте каталог Models в корневую папку проекта.
Добавьте класс
Book
в каталог Models с помощью такого кода:using MongoDB.Bson; using MongoDB.Bson.Serialization.Attributes; namespace BooksApi.Models { public class Book { [BsonId] [BsonRepresentation(BsonType.ObjectId)] public string Id { get; set; } [BsonElement("Name")] public string BookName { get; set; } public decimal Price { get; set; } public string Category { get; set; } public string Author { get; set; } } }
В классе выше свойство
Id
:- Требуется для сопоставления объекта среды CLR с коллекцией MongoDB.
- Помечается с помощью
[BsonId]
для назначения этого свойства в качестве первичного ключа документа. - Помечается с помощью
[BsonRepresentation(BsonType.ObjectId)]
, чтобы разрешить передачу параметра в качестве типаstring
вместо структуры ObjectId. Mongo обрабатывает преобразование изstring
вObjectId
.
Свойство
BookName
помечено атрибутом[BsonElement]
. Значение атрибутаName
представляет имя свойства в коллекции MongoDB.
Добавление модели конфигурации
Добавьте в файл
appsettings.json
следующие значения конфигурации базы данных:{ "BookstoreDatabaseSettings": { "BooksCollectionName": "Books", "ConnectionString": "mongodb://localhost:27017", "DatabaseName": "BookstoreDb" }, "Logging": { "IncludeScopes": false, "Debug": { "LogLevel": { "Default": "Warning" } }, "Console": { "LogLevel": { "Default": "Warning" } } } }
BookstoreDatabaseSettings.cs
Добавьте файл в каталог Models со следующим кодом:namespace BooksApi.Models { public class BookstoreDatabaseSettings : IBookstoreDatabaseSettings { public string BooksCollectionName { get; set; } public string ConnectionString { get; set; } public string DatabaseName { get; set; } } public interface IBookstoreDatabaseSettings { string BooksCollectionName { get; set; } string ConnectionString { get; set; } string DatabaseName { get; set; } } }
Предыдущий класс
BookstoreDatabaseSettings
используется для хранения значений свойствBookstoreDatabaseSettings
файлаappsettings.json
. Свойства 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(); }
В предыдущем коде:
- Экземпляр конфигурации, к которому привязан раздел
BookstoreDatabaseSettings
файлаappsettings.json
, зарегистрирован в контейнере внедрения зависимостей (DI). Например, свойствоConnectionString
объектаBookstoreDatabaseSettings
заполняется свойствомBookstoreDatabaseSettings:ConnectionString
в файлеappsettings.json
. - Интерфейс
IBookstoreDatabaseSettings
регистрируется в DI с использованием времени существования отдельной службы. При внедрении экземпляр интерфейса разрешается в объектBookstoreDatabaseSettings
.
- Экземпляр конфигурации, к которому привязан раздел
Добавьте следующий код в самое начало файла
Startup.cs
, чтобы разрешить ссылкиBookstoreDatabaseSettings
иIBookstoreDatabaseSettings
:using BooksApi.Models;
Добавление службы операций CRUD
Добавьте каталог Services в корневую папку проекта.
Добавьте класс
BookService
в каталог Services с помощью такого кода:using BooksApi.Models; using MongoDB.Driver; using System.Collections.Generic; using System.Linq; namespace BooksApi.Services { public class BookService { private readonly IMongoCollection<Book> _books; public BookService(IBookstoreDatabaseSettings settings) { var client = new MongoClient(settings.ConnectionString); var database = client.GetDatabase(settings.DatabaseName); _books = database.GetCollection<Book>(settings.BooksCollectionName); } public List<Book> Get() => _books.Find(book => true).ToList(); public Book Get(string id) => _books.Find<Book>(book => book.Id == id).FirstOrDefault(); public Book Create(Book book) { _books.InsertOne(book); return book; } public void Update(string id, Book bookIn) => _books.ReplaceOne(book => book.Id == id, bookIn); public void Remove(Book bookIn) => _books.DeleteOne(book => book.Id == bookIn.Id); public void Remove(string id) => _books.DeleteOne(book => book.Id == id); } }
В предыдущем коде экземпляр
IBookstoreDatabaseSettings
извлекается из DI посредством внедрения конструктора. Таким образом обеспечивается доступ к значениям конфигурации в файлеappsettings.json
, которые были добавлены в разделе Добавление модели конфигурации.Добавьте выделенный ниже код в
Startup.ConfigureServices
:public void ConfigureServices(IServiceCollection services) { services.Configure<BookstoreDatabaseSettings>( Configuration.GetSection(nameof(BookstoreDatabaseSettings))); services.AddSingleton<IBookstoreDatabaseSettings>(sp => sp.GetRequiredService<IOptions<BookstoreDatabaseSettings>>().Value); services.AddSingleton<BookService>(); services.AddControllers(); }
В предыдущем коде класс
BookService
регистрируется в DI, чтобы обеспечить поддержку внедрения через конструктор в используемые классы. Время существования отдельной службы — наиболее подходящий вариант, так какBookService
имеет прямую зависимость отMongoClient
. В соответствии с официальными правилами повторного использования клиента MongoMongoClient
следует регистрировать в 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 для выполнения операций. В этом руководстве используется универсальный метод GetCollection<TDocument>(collection) интерфейса для получения доступа к данным в определенной коллекции. Выполняйте операции CRUD с коллекцией после вызова этого метода. В вызове метода
GetCollection<TDocument>(collection)
:collection
представляет имя коллекции;TDocument
представляет тип объекта среды CLR, хранящегося в коллекции;
GetCollection<TDocument>(collection)
возвращает объект MongoCollection, представляющий коллекцию. В этом руководстве следующие методы вызываются для коллекции:
- DeleteOne: удаляет один документ, соответствующий заданным критериям поиска.
- Find<TDocument> — возвращает все документы в коллекции, соответствующие заданным критериям поиска.
- InsertOne: вставляет предоставленный объект в качестве нового документа в коллекцию.
- ReplaceOne: заменяет один документ, соответствующий предоставленным условиям поиска, предоставленным объектом.
Добавление контроллера
Добавьте класс BooksController
в каталог Controllers с помощью такого кода:
using BooksApi.Models;
using BooksApi.Services;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
namespace BooksApi.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class BooksController : ControllerBase
{
private readonly BookService _bookService;
public BooksController(BookService bookService)
{
_bookService = bookService;
}
[HttpGet]
public ActionResult<List<Book>> Get() =>
_bookService.Get();
[HttpGet("{id:length(24)}", Name = "GetBook")]
public ActionResult<Book> Get(string id)
{
var book = _bookService.Get(id);
if (book == null)
{
return NotFound();
}
return book;
}
[HttpPost]
public ActionResult<Book> Create(Book book)
{
_bookService.Create(book);
return CreatedAtRoute("GetBook", new { id = book.Id.ToString() }, book);
}
[HttpPut("{id:length(24)}")]
public IActionResult Update(string id, Book bookIn)
{
var book = _bookService.Get(id);
if (book == null)
{
return NotFound();
}
_bookService.Update(id, bookIn);
return NoContent();
}
[HttpDelete("{id:length(24)}")]
public IActionResult Delete(string id)
{
var book = _bookService.Get(id);
if (book == null)
{
return NotFound();
}
_bookService.Remove(id);
return NoContent();
}
}
}
Предыдущий контроллер веб-API:
- использует класс
BookService
для выполнения операций CRUD; - содержит методы действий для поддержки запросов HTTP GET, POST, PUT и DELETE.
- Вызывает CreatedAtRoute в методе действия
Create
для возврата ответа HTTP 201. Код состояния 201 представляет собой стандартный ответ метода HTTP POST, создающего ресурс на сервере.CreatedAtRoute
также добавляет заголовокLocation
в ответ. ЗаголовокLocation
указывает универсальный код ресурса (URI) созданной книги.
Тестирование веб-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
Нужно изменить два параметра для возвращаемых ответов JSON в разделе Тестирование веб-API:
- Смешанный регистр имен свойств по умолчанию следует изменить в соответствии с регистром Pascal имен свойств объекта CLR.
- Свойство
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()); }
После предыдущего изменения имена свойств в ответе сериализованного JSON веб-API соответствуют именам свойств в типе объекта CLR. Например, свойство
Author
классаBook
сериализуется какAuthor
.В
Models/Book.cs
, заметитеBookName
свойство со следующим[JsonProperty]
атрибутом:[BsonElement("Name")] [JsonProperty("Name")] public string BookName { get; set; }
Атрибут
[JsonProperty]
со значениемName
представляет имя свойства в сериализованном ответе веб-API в формате JSON.Добавьте следующий код в самое начало файла
Models/Book.cs
, чтобы разрешить ссылку на атрибут[JsonProperty]
:using Newtonsoft.Json;
Повторите действия, описанные в разделе Тестирование веб-API. Обратите внимание на различие в именах свойств JSON.
Добавление поддержки аутентификации в веб-API
ASP.NET Core Identity позволяет использовать функцию входа в пользовательском интерфейсе для веб-приложений ASP.NET Core. Чтобы защитить веб-API и одностраничные приложения, используйте один из следующих способов:
- Microsoft Entra ID
- Azure Active Directory B2C (Azure AD B2C)
- Duende IdentityServer. Duende IdentityServer — это сторонний продукт.
Duende Identity Server — это платформа OpenID Connect и OAuth 2.0 для ASP.NET Core. Duende Identity Server включает следующие функции безопасности:
- Проверка подлинности как услуга (AaaS)
- Единый вход (SSO) для нескольких типов приложений
- Контроль доступа для API
- Шлюз федерации
Дополнительные сведения см. в разделе "Обзор сервера DuendeIdentity".
Дополнительные сведения о других поставщиках проверки подлинности см. в разделе "Параметры проверки подлинности Community OSS" для ASP.NET Core
Следующие шаги
Дополнительные сведения о сборке веб-API ASP.NET Core см. в этих статьях:
ASP.NET Core
Обратная связь
https://aka.ms/ContentUserFeedback.
Ожидается в ближайшее время: в течение 2024 года мы постепенно откажемся от GitHub Issues как механизма обратной связи для контента и заменим его новой системой обратной связи. Дополнительные сведения см. в разделеОтправить и просмотреть отзыв по