Создание веб-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 и веб-разработка.

    Рабочие нагрузки установщика VS22

настроить MongoDB;

Включите доступ к Оболочке MongoDB и MongoDB из любого места на компьютере разработки (Windows/Linux/macOS):

  1. Скачайте и установите оболочку MongoDB:

    • macOS/Linux: выберите каталог для извлечения оболочки MongoDB в. Добавьте полученный путь к mongosh переменной PATH среды.
    • Windows: Оболочка MongoDB (mongosh.exe) устанавливается в C:\Users<\user>\AppData\Local\Programs\mongosh. Добавьте полученный путь к mongosh.exe переменной PATH среды.
  2. Скачайте и установите MongoDB:

    • macOS/Linux: проверьте каталог, по которому был установлен MongoDB, обычно в /usr/local/mongodb. Добавьте полученный путь к mongodb переменной PATH среды.
    • Windows: MongoDB устанавливается в C:\Program Files\MongoDB по умолчанию. Добавьте C:\Program Files\MongoDB\Server\<version_number>\bin в переменную среды PATH.
  3. Выберите каталог служба хранилища данных: выберите каталог на компьютере разработки для хранения данных. Если такого каталога нет, создайте его. Оболочка MongoDB не создает новые каталоги:

    • macOS/Linux: например, /usr/local/var/mongodb.
    • Windows: например, C:\\BooksData.
  4. В командной оболочке ОС (а не в оболочке MongoDB) используйте следующую команду, чтобы подключиться к MongoDB через порт 27017 по умолчанию. Замените <data_directory_path> каталог, выбранный на предыдущем шаге.

    mongod --dbpath <data_directory_path>
    

В следующих шагах используйте ранее установленный интерфейс MongoDB, чтобы создать базу данных и коллекции и сохранить документы. Дополнительные сведения о командах MongoDB: mongosh.

  1. Откройте экземпляр командной оболочки MongoDB, запуская mongosh.exe.

  2. В командной оболочке подключитесь к тестовой базе данных по умолчанию, выполнив следующую команду:

    mongosh
    
  3. Выполните приведенную ниже команду в командной оболочке.

    use BookStore
    

    Будет создана база данных с именем BookStore, если она не существует. Если такая база данных существует, для нее уже установлено подключение для транзакций.

  4. Создайте коллекцию Books с помощью такой команды:

    db.createCollection('Books')
    

    Отобразится такой результат:

    { "ok" : 1 }
    
  5. Определите схему для коллекции Books и вставьте два документа, используя следующую команду:

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

    Отобразится примерно такой результат:

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

    Примечание.

    Приведенные ObjectIdвыше результаты не соответствуют приведенным в командной оболочке.

  6. Просмотрите документы в базе данных, используя такую команду:

    db.Books.find().pretty()
    

    Отобразится примерно такой результат:

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

    Схема добавляет автоматически созданное свойство _id типа ObjectId к каждому документу.

Создание проекта веб-API ASP.NET Core

  1. Выберите Файл>Создать>Проект.

  2. Выберите тип проекта Веб-API ASP.NET Core и щелкните Далее.

  3. Назовите проект BookStoreApi и щелкните Создать.

  4. Выберите платформу .NET 8.0 (долгосрочная поддержка) и нажмите кнопку "Создать".

  5. В окне Консоль диспетчера пакетов перейдите в корневую папку проекта. Выполните следующую команду, чтобы установить драйвер .NET для MongoDB:

    Install-Package MongoDB.Driver
    

Добавление модели сущности

  1. Добавьте каталог Models в корневую папку проекта.

  2. Добавьте класс Book в каталог Models с помощью такого кода:

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

    В классе выше свойство Id:

    • Требуется для сопоставления объекта среды CLR с коллекцией MongoDB.
    • Помечается с помощью [BsonId] для назначения этого свойства в качестве первичного ключа документа.
    • Помечается с помощью [BsonRepresentation(BsonType.ObjectId)], чтобы разрешить передачу параметра в качестве типа string вместо структуры ObjectId. Mongo обрабатывает преобразование из string в ObjectId.

    Свойство BookName помечено атрибутом [BsonElement]. Значение атрибута Name представляет имя свойства в коллекции MongoDB.

Добавление модели конфигурации

  1. Добавьте в файл appsettings.json следующие значения конфигурации базы данных:

    {
        "BookStoreDatabase": {
            "ConnectionString": "mongodb://localhost:27017",
            "DatabaseName": "BookStore",
            "BooksCollectionName": "Books"
        },
        "Logging": {
            "LogLevel": {
                "Default": "Information",
                "Microsoft.AspNetCore": "Warning"
            }
        },
        "AllowedHosts": "*"
    }
    
  2. Добавьте класс BookStoreDatabaseSettings в каталог Models с помощью такого кода:

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

    Предыдущий класс BookStoreDatabaseSettings используется для хранения значений свойств BookStoreDatabase файла appsettings.json. Свойства JSON и C# имеют одинаковые имена, что упрощает сопоставление.

  3. Добавьте выделенный ниже код в 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.

  4. Добавьте следующий код в самое начало файла Program.cs, чтобы разрешить ссылку BookStoreDatabaseSettings:

    using BookStoreApi.Models;
    

Добавление службы операций CRUD

  1. Добавьте каталог Services в корневую папку проекта.

  2. Добавьте класс BooksService в каталог Services с помощью такого кода:

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

    В предыдущем коде экземпляр BookStoreDatabaseSettings извлекается из DI путем внедрения конструктора. Таким образом обеспечивается доступ к значениям конфигурации в файле appsettings.json, которые были добавлены в разделе Добавление модели конфигурации.

  3. Добавьте выделенный ниже код в Program.cs:

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

    В предыдущем коде класс BooksService регистрируется в DI, чтобы обеспечить поддержку внедрения через конструктор в используемые классы. Время существования отдельной службы — наиболее подходящий вариант, так как BooksService имеет прямую зависимость от MongoClient. В соответствии с официальными правилами повторного использования клиента MongoMongoClient следует регистрировать в DI с использованием времени существования отдельной службы.

  4. Добавьте следующий код в самое начало файла Program.cs, чтобы разрешить ссылку BooksService:

    using BookStoreApi.Services;
    

Класс BooksService использует следующие члены MongoDB.Driver для выполнения операций CRUD с базой данных:

  • MongoClient — считывает экземпляр сервера для выполнения операций с базой данных. Конструктор этого класса предоставляется в строка подключения MongoDB:

    public BooksService(
        IOptions<BookStoreDatabaseSettings> bookStoreDatabaseSettings)
    {
        var mongoClient = new MongoClient(
            bookStoreDatabaseSettings.Value.ConnectionString);
    
        var mongoDatabase = mongoClient.GetDatabase(
            bookStoreDatabaseSettings.Value.DatabaseName);
    
        _booksCollection = mongoDatabase.GetCollection<Book>(
            bookStoreDatabaseSettings.Value.BooksCollectionName);
    }
    
  • IMongoDatabase — представляет базу данных Mongo для выполнения операций. В этом руководстве используется универсальный метод GetCollection<TDocument>(collection) интерфейса для получения доступа к данным в определенной коллекции. Выполняйте операции CRUD с коллекцией после вызова этого метода. В вызове метода GetCollection<TDocument>(collection):

    • collection представляет имя коллекции;
    • TDocument представляет тип объекта среды CLR, хранящегося в коллекции;

GetCollection<TDocument>(collection) возвращает объект MongoCollection, представляющий коллекцию. В этом руководстве следующие методы вызываются для коллекции:

  • 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

  1. Выполните сборку и запустите приложение.

  2. Перейдите к https://localhost:<port>/api/booksразделу , где <port> автоматически назначенный номер порта для приложения, чтобы проверить метод действия без параметров Get контроллера, нажмите кнопку "Попробовать выполнить".> Отобразится примерно такой ответ JSON:

    [
      {
        "id": "61a6058e6c43f32854e51f51",
        "bookName": "Design Patterns",
        "price": 54.93,
        "category": "Computers",
        "author": "Ralph Johnson"
      },
      {
        "id": "61a6058e6c43f32854e51f52",
        "bookName": "Clean Code",
        "price": 43.15,
        "category": "Computers",
        "author": "Robert C. Martin"
      }
    ]
    
  3. Перейдите по адресу https://localhost:<port>/api/books/{id here}, чтобы протестировать перегруженный метод действия Get контроллера. Отобразится примерно такой ответ JSON:

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

Настройка параметров сериализации JSON

Нужно изменить два параметра для возвращаемых ответов JSON в разделе Тестирование веб-API:

  • Смешанный регистр имен свойств по умолчанию следует изменить в соответствии с регистром Pascal имен свойств объекта CLR.
  • Свойство bookName должно возвращаться как Name.

Чтобы удовлетворить эти требования, внесите следующие изменения:

  1. В Program.cs вставьте следующий выделенный код в вызов метода AddControllers:

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

    После предыдущего изменения имена свойств в ответе сериализованного JSON веб-API соответствуют именам свойств в типе объекта CLR. Например, свойство Author класса Book сериализуется как Author, а не author.

  2. В Models/Book.cs добавьте к свойству BookName атрибут [JsonPropertyName]:

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

    Атрибут [JsonPropertyName] со значением Name представляет имя свойства в сериализованном ответе веб-API в формате JSON.

  3. Добавьте следующий код в самое начало файла Models/Book.cs, чтобы разрешить ссылку на атрибут [JsonProperty]:

    using System.Text.Json.Serialization;
    
  4. Повторите действия, описанные в разделе Тестирование веб-API. Обратите внимание на различие в именах свойств JSON.

Добавление поддержки аутентификации в веб-API

ASP.NET Core Identity позволяет использовать функцию входа в пользовательском интерфейсе для веб-приложений ASP.NET Core. Чтобы защитить веб-API и одностраничные приложения, используйте один из следующих способов:

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 и веб-разработка.

    Рабочие нагрузки установщика VS22

настроить MongoDB;

Включите доступ к оболочке MongoDB и Mongo DB из любого места на компьютере разработки:

  1. В Windows MongoDB по умолчанию устанавливается в папку C:\Program Files\MongoDB. Добавьте C:\Program Files\MongoDB\Server\<version_number>\bin в переменную среды PATH.

  2. Скачайте оболочку MongoDB и выберите каталог, чтобы извлечь его. Добавьте полученный путь к mongosh.exe переменной PATH среды.

  3. Выберите каталог на компьютере разработки для хранения данных. Например C:\BooksData при работе в Windows. Если такого каталога нет, создайте его. В mongo Shell нельзя создавать каталоги.

  4. В командной оболочке ОС (а не в оболочке MongoDB) используйте следующую команду, чтобы подключиться к MongoDB через порт 27017 по умолчанию. Замените <data_directory_path> каталог, выбранный на предыдущем шаге.

    mongod --dbpath <data_directory_path>
    

В следующих шагах используйте ранее установленный интерфейс MongoDB, чтобы создать базу данных и коллекции и сохранить документы. Дополнительные сведения о командах MongoDB: mongosh.

  1. Откройте экземпляр командной оболочки MongoDB, запуская mongosh.exe.

  2. В командной оболочке подключитесь к тестовой базе данных по умолчанию, выполнив следующую команду:

    mongosh
    
  3. Выполните приведенную ниже команду в командной оболочке.

    use BookStore
    

    Будет создана база данных с именем BookStore, если она не существует. Если такая база данных существует, для нее уже установлено подключение для транзакций.

  4. Создайте коллекцию Books с помощью такой команды:

    db.createCollection('Books')
    

    Отобразится такой результат:

    { "ok" : 1 }
    
  5. Определите схему для коллекции Books и вставьте два документа, используя следующую команду:

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

    Отобразится примерно такой результат:

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

    Примечание.

    Приведенные ObjectIdвыше результаты не соответствуют приведенным в командной оболочке.

  6. Просмотрите документы в базе данных, используя такую команду:

    db.Books.find().pretty()
    

    Отобразится примерно такой результат:

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

    Схема добавляет автоматически созданное свойство _id типа ObjectId к каждому документу.

Создание проекта веб-API ASP.NET Core

  1. Выберите Файл>Создать>Проект.

  2. Выберите тип проекта Веб-API ASP.NET Core и щелкните Далее.

  3. Назовите проект BookStoreApi и щелкните Создать.

  4. Выберите платформу .NET 7.0 (стандартная поддержка терминов) и нажмите кнопку "Создать".

  5. В меню Сервис последовательно выберите пункты Диспетчер пакетов NuGet>Консоль диспетчера пакетов.

  6. В окне Консоль диспетчера пакетов перейдите в корневую папку проекта. Выполните следующую команду, чтобы установить драйвер .NET для MongoDB:

    Install-Package MongoDB.Driver
    

Добавление модели сущности

  1. Добавьте каталог Models в корневую папку проекта.

  2. Добавьте класс Book в каталог Models с помощью такого кода:

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

    В классе выше свойство Id:

    • Требуется для сопоставления объекта среды CLR с коллекцией MongoDB.
    • Помечается с помощью [BsonId] для назначения этого свойства в качестве первичного ключа документа.
    • Помечается с помощью [BsonRepresentation(BsonType.ObjectId)], чтобы разрешить передачу параметра в качестве типа string вместо структуры ObjectId. Mongo обрабатывает преобразование из string в ObjectId.

    Свойство BookName помечено атрибутом [BsonElement]. Значение атрибута Name представляет имя свойства в коллекции MongoDB.

Добавление модели конфигурации

  1. Добавьте в файл appsettings.json следующие значения конфигурации базы данных:

    {
      "BookStoreDatabase": {
        "ConnectionString": "mongodb://localhost:27017",
        "DatabaseName": "BookStore",
        "BooksCollectionName": "Books"
      },
      "Logging": {
        "LogLevel": {
          "Default": "Information",
          "Microsoft.AspNetCore": "Warning"
        }
      },
      "AllowedHosts": "*"
    }
    
  2. Добавьте класс BookStoreDatabaseSettings в каталог Models с помощью такого кода:

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

    Предыдущий класс BookStoreDatabaseSettings используется для хранения значений свойств BookStoreDatabase файла appsettings.json. Свойства JSON и C# имеют одинаковые имена, что упрощает сопоставление.

  3. Добавьте выделенный ниже код в 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.

  4. Добавьте следующий код в самое начало файла Program.cs, чтобы разрешить ссылку BookStoreDatabaseSettings:

    using BookStoreApi.Models;
    

Добавление службы операций CRUD

  1. Добавьте каталог Services в корневую папку проекта.

  2. Добавьте класс BooksService в каталог Services с помощью такого кода:

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

    В предыдущем коде экземпляр BookStoreDatabaseSettings извлекается из DI путем внедрения конструктора. Таким образом обеспечивается доступ к значениям конфигурации в файле appsettings.json, которые были добавлены в разделе Добавление модели конфигурации.

  3. Добавьте выделенный ниже код в Program.cs:

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

    В предыдущем коде класс BooksService регистрируется в DI, чтобы обеспечить поддержку внедрения через конструктор в используемые классы. Время существования отдельной службы — наиболее подходящий вариант, так как BooksService имеет прямую зависимость от MongoClient. В соответствии с официальными правилами повторного использования клиента MongoMongoClient следует регистрировать в DI с использованием времени существования отдельной службы.

  4. Добавьте следующий код в самое начало файла Program.cs, чтобы разрешить ссылку BooksService:

    using BookStoreApi.Services;
    

Класс BooksService использует следующие члены MongoDB.Driver для выполнения операций CRUD с базой данных:

  • MongoClient — считывает экземпляр сервера для выполнения операций с базой данных. Конструктор этого класса предоставляет строку подключения MongoDB.

    public BooksService(
        IOptions<BookStoreDatabaseSettings> bookStoreDatabaseSettings)
    {
        var mongoClient = new MongoClient(
            bookStoreDatabaseSettings.Value.ConnectionString);
    
        var mongoDatabase = mongoClient.GetDatabase(
            bookStoreDatabaseSettings.Value.DatabaseName);
    
        _booksCollection = mongoDatabase.GetCollection<Book>(
            bookStoreDatabaseSettings.Value.BooksCollectionName);
    }
    
  • IMongoDatabase — представляет базу данных Mongo для выполнения операций. В этом руководстве используется универсальный метод GetCollection<TDocument>(collection) интерфейса для получения доступа к данным в определенной коллекции. Выполняйте операции CRUD с коллекцией после вызова этого метода. В вызове метода GetCollection<TDocument>(collection):

    • collection представляет имя коллекции;
    • TDocument представляет тип объекта среды CLR, хранящегося в коллекции;

GetCollection<TDocument>(collection) возвращает объект MongoCollection, представляющий коллекцию. В этом руководстве следующие методы вызываются для коллекции:

  • 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

  1. Выполните сборку и запустите приложение.

  2. Перейдите к https://localhost:<port>/api/books, где <port> — это автоматически назначаемый номер порта для приложения, чтобы протестировать метод действия Get контроллера без параметров. Отобразится примерно такой ответ JSON:

    [
      {
        "id": "61a6058e6c43f32854e51f51",
        "bookName": "Design Patterns",
        "price": 54.93,
        "category": "Computers",
        "author": "Ralph Johnson"
      },
      {
        "id": "61a6058e6c43f32854e51f52",
        "bookName": "Clean Code",
        "price": 43.15,
        "category": "Computers",
        "author": "Robert C. Martin"
      }
    ]
    
  3. Перейдите по адресу https://localhost:<port>/api/books/{id here}, чтобы протестировать перегруженный метод действия Get контроллера. Отобразится примерно такой ответ JSON:

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

Настройка параметров сериализации JSON

Нужно изменить два параметра для возвращаемых ответов JSON в разделе Тестирование веб-API:

  • Смешанный регистр имен свойств по умолчанию следует изменить в соответствии с регистром Pascal имен свойств объекта CLR.
  • Свойство bookName должно возвращаться как Name.

Чтобы удовлетворить эти требования, внесите следующие изменения:

  1. В Program.cs вставьте следующий выделенный код в вызов метода AddControllers:

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

    После предыдущего изменения имена свойств в ответе сериализованного JSON веб-API соответствуют именам свойств в типе объекта CLR. Например, свойство Author класса Book сериализуется как Author, а не author.

  2. В Models/Book.cs добавьте к свойству BookName атрибут [JsonPropertyName]:

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

    Атрибут [JsonPropertyName] со значением Name представляет имя свойства в сериализованном ответе веб-API в формате JSON.

  3. Добавьте следующий код в самое начало файла Models/Book.cs, чтобы разрешить ссылку на атрибут [JsonProperty]:

    using System.Text.Json.Serialization;
    
  4. Повторите действия, описанные в разделе Тестирование веб-API. Обратите внимание на различие в именах свойств JSON.

Добавление поддержки аутентификации в веб-API

ASP.NET Core Identity позволяет использовать функцию входа в пользовательском интерфейсе для веб-приложений ASP.NET Core. Чтобы защитить веб-API и одностраничные приложения, используйте один из следующих способов:

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

Необходимые компоненты

настроить MongoDB;

Включите доступ к оболочке MongoDB и Mongo DB из любого места на компьютере разработки:

  1. В Windows MongoDB по умолчанию устанавливается в папку C:\Program Files\MongoDB. Добавьте C:\Program Files\MongoDB\Server\<version_number>\bin в переменную среды PATH.

  2. Скачайте оболочку MongoDB и выберите каталог, чтобы извлечь его. Добавьте полученный путь к mongosh.exe переменной PATH среды.

  3. Выберите каталог на компьютере разработки для хранения данных. Например C:\BooksData при работе в Windows. Если такого каталога нет, создайте его. В mongo Shell нельзя создавать каталоги.

  4. В командной оболочке ОС (а не в оболочке MongoDB) используйте следующую команду, чтобы подключиться к MongoDB через порт 27017 по умолчанию. Замените <data_directory_path> каталог, выбранный на предыдущем шаге.

    mongod --dbpath <data_directory_path>
    

В следующих шагах используйте ранее установленный интерфейс MongoDB, чтобы создать базу данных и коллекции и сохранить документы. Дополнительные сведения о командах MongoDB: mongosh.

  1. Откройте экземпляр командной оболочки MongoDB, запуская mongosh.exe.

  2. В командной оболочке подключитесь к тестовой базе данных по умолчанию, выполнив следующую команду:

    mongosh
    
  3. Выполните приведенную ниже команду в командной оболочке.

    use BookStore
    

    Будет создана база данных с именем BookStore, если она не существует. Если такая база данных существует, для нее уже установлено подключение для транзакций.

  4. Создайте коллекцию Books с помощью такой команды:

    db.createCollection('Books')
    

    Отобразится такой результат:

    { "ok" : 1 }
    
  5. Определите схему для коллекции Books и вставьте два документа, используя следующую команду:

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

    Отобразится примерно такой результат:

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

    Примечание.

    Приведенные ObjectIdвыше результаты не соответствуют приведенным в командной оболочке.

  6. Просмотрите документы в базе данных, используя такую команду:

    db.Books.find().pretty()
    

    Отобразится примерно такой результат:

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

    Схема добавляет автоматически созданное свойство _id типа ObjectId к каждому документу.

Создание проекта веб-API ASP.NET Core

  1. Выберите Файл>Создать>Проект.

  2. Выберите тип проекта Веб-API ASP.NET Core и щелкните Далее.

  3. Назовите проект BookStoreApi и щелкните Создать.

  4. Выберите платформу .NET 6.0 (долгосрочная поддержка) и щелкните Создать.

  5. В окне Консоль диспетчера пакетов перейдите в корневую папку проекта. Выполните следующую команду, чтобы установить драйвер .NET для MongoDB:

    Install-Package MongoDB.Driver
    

Добавление модели сущности

  1. Добавьте каталог Models в корневую папку проекта.

  2. Добавьте класс Book в каталог Models с помощью такого кода:

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

    В классе выше свойство Id:

    • Требуется для сопоставления объекта среды CLR с коллекцией MongoDB.
    • Помечается с помощью [BsonId] для назначения этого свойства в качестве первичного ключа документа.
    • Помечается с помощью [BsonRepresentation(BsonType.ObjectId)], чтобы разрешить передачу параметра в качестве типа string вместо структуры ObjectId. Mongo обрабатывает преобразование из string в ObjectId.

    Свойство BookName помечено атрибутом [BsonElement]. Значение атрибута Name представляет имя свойства в коллекции MongoDB.

Добавление модели конфигурации

  1. Добавьте в файл appsettings.json следующие значения конфигурации базы данных:

    {
        "BookStoreDatabase": {
            "ConnectionString": "mongodb://localhost:27017",
            "DatabaseName": "BookStore",
            "BooksCollectionName": "Books"
        },
        "Logging": {
            "LogLevel": {
                "Default": "Information",
                "Microsoft.AspNetCore": "Warning"
            }
        },
        "AllowedHosts": "*"
    }
    
  2. Добавьте класс BookStoreDatabaseSettings в каталог Models с помощью такого кода:

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

    Предыдущий класс BookStoreDatabaseSettings используется для хранения значений свойств BookStoreDatabase файла appsettings.json. Свойства JSON и C# имеют одинаковые имена, что упрощает сопоставление.

  3. Добавьте выделенный ниже код в 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.

  4. Добавьте следующий код в самое начало файла Program.cs, чтобы разрешить ссылку BookStoreDatabaseSettings:

    using BookStoreApi.Models;
    

Добавление службы операций CRUD

  1. Добавьте каталог Services в корневую папку проекта.

  2. Добавьте класс BooksService в каталог Services с помощью такого кода:

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

    В предыдущем коде экземпляр BookStoreDatabaseSettings извлекается из DI путем внедрения конструктора. Таким образом обеспечивается доступ к значениям конфигурации в файле appsettings.json, которые были добавлены в разделе Добавление модели конфигурации.

  3. Добавьте выделенный ниже код в Program.cs:

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

    В предыдущем коде класс BooksService регистрируется в DI, чтобы обеспечить поддержку внедрения через конструктор в используемые классы. Время существования отдельной службы — наиболее подходящий вариант, так как BooksService имеет прямую зависимость от MongoClient. В соответствии с официальными правилами повторного использования клиента MongoMongoClient следует регистрировать в DI с использованием времени существования отдельной службы.

  4. Добавьте следующий код в самое начало файла Program.cs, чтобы разрешить ссылку BooksService:

    using BookStoreApi.Services;
    

Класс BooksService использует следующие члены MongoDB.Driver для выполнения операций CRUD с базой данных:

  • MongoClient — считывает экземпляр сервера для выполнения операций с базой данных. Конструктор этого класса предоставляет строку подключения MongoDB.

    public BooksService(
        IOptions<BookStoreDatabaseSettings> bookStoreDatabaseSettings)
    {
        var mongoClient = new MongoClient(
            bookStoreDatabaseSettings.Value.ConnectionString);
    
        var mongoDatabase = mongoClient.GetDatabase(
            bookStoreDatabaseSettings.Value.DatabaseName);
    
        _booksCollection = mongoDatabase.GetCollection<Book>(
            bookStoreDatabaseSettings.Value.BooksCollectionName);
    }
    
  • IMongoDatabase — представляет базу данных Mongo для выполнения операций. В этом руководстве используется универсальный метод GetCollection<TDocument>(collection) интерфейса для получения доступа к данным в определенной коллекции. Выполняйте операции CRUD с коллекцией после вызова этого метода. В вызове метода GetCollection<TDocument>(collection):

    • collection представляет имя коллекции;
    • TDocument представляет тип объекта среды CLR, хранящегося в коллекции;

GetCollection<TDocument>(collection) возвращает объект MongoCollection, представляющий коллекцию. В этом руководстве следующие методы вызываются для коллекции:

  • 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

  1. Выполните сборку и запустите приложение.

  2. Перейдите к https://localhost:<port>/api/books, где <port> — это автоматически назначаемый номер порта для приложения, чтобы протестировать метод действия Get контроллера без параметров. Отобразится примерно такой ответ JSON:

    [
      {
        "id": "61a6058e6c43f32854e51f51",
        "bookName": "Design Patterns",
        "price": 54.93,
        "category": "Computers",
        "author": "Ralph Johnson"
      },
      {
        "id": "61a6058e6c43f32854e51f52",
        "bookName": "Clean Code",
        "price": 43.15,
        "category": "Computers",
        "author": "Robert C. Martin"
      }
    ]
    
  3. Перейдите по адресу https://localhost:<port>/api/books/{id here}, чтобы протестировать перегруженный метод действия Get контроллера. Отобразится примерно такой ответ JSON:

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

Настройка параметров сериализации JSON

Нужно изменить два параметра для возвращаемых ответов JSON в разделе Тестирование веб-API:

  • Смешанный регистр имен свойств по умолчанию следует изменить в соответствии с регистром Pascal имен свойств объекта CLR.
  • Свойство bookName должно возвращаться как Name.

Чтобы удовлетворить эти требования, внесите следующие изменения:

  1. В Program.cs вставьте следующий выделенный код в вызов метода AddControllers:

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

    После предыдущего изменения имена свойств в ответе сериализованного JSON веб-API соответствуют именам свойств в типе объекта CLR. Например, свойство Author класса Book сериализуется как Author, а не author.

  2. В Models/Book.cs добавьте к свойству BookName атрибут [JsonPropertyName]:

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

    Атрибут [JsonPropertyName] со значением Name представляет имя свойства в сериализованном ответе веб-API в формате JSON.

  3. Добавьте следующий код в самое начало файла Models/Book.cs, чтобы разрешить ссылку на атрибут [JsonProperty]:

    using System.Text.Json.Serialization;
    
  4. Повторите действия, описанные в разделе Тестирование веб-API. Обратите внимание на различие в именах свойств JSON.

Добавление поддержки аутентификации в веб-API

ASP.NET Core Identity позволяет использовать функцию входа в пользовательском интерфейсе для веб-приложений ASP.NET Core. Чтобы защитить веб-API и одностраничные приложения, используйте один из следующих способов:

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

Просмотреть или скачать образец кода (описание загрузки)

Необходимые компоненты

настроить MongoDB;

Если используется Windows, MongoDB по умолчанию устанавливается в папку C:\Program Files\MongoDB. Добавьте C:\Program Files\MongoDB\Server\<version_number>\bin в переменную среды Path. Это изменение обеспечит доступ к MongoDB из любого места на компьютере разработки.

В следующих шагах используйте интерфейс mongo Shell, чтобы создать базу данных и коллекции и сохранить документы. Дополнительные сведения о командах mongo Shell см. в руководстве по работе с mongo Shell.

  1. Выберите папку на компьютере разработки для хранения данных. Например C:\BooksData при работе в Windows. Если такого каталога нет, создайте его. В mongo Shell нельзя создавать каталоги.

  2. Откройте командную оболочку. Выполните следующую команду для подключения к MongoDB через порт 27017, заданный по умолчанию. Не забудьте заменить <data_directory_path> каталогом, созданным на предыдущем этапе.

    mongod --dbpath <data_directory_path>
    
  3. Откройте другой экземпляр командной оболочки. Подключитесь к тестовой базе данных по умолчанию, выполнив такую команду:

    mongo
    
  4. В командной оболочке выполните следующую команду:

    use BookstoreDb
    

    Будет создана база данных с именем BookstoreDb, если она не существует. Если такая база данных существует, для нее уже установлено подключение для транзакций.

  5. Создайте коллекцию Books с помощью такой команды:

    db.createCollection('Books')
    

    Отобразится такой результат:

    { "ok" : 1 }
    
  6. Определите схему для коллекции Books и вставьте два документа, используя следующую команду:

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

    Отобразится такой результат:

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

    Примечание.

    Идентификаторы в этой статье не будут соответствовать идентификаторам в запущенном примере.

  7. Просмотрите документы в базе данных, используя такую команду:

    db.Books.find({}).pretty()
    

    Отобразится такой результат:

    {
      "_id" : ObjectId("5bfd996f7b8e48dc15ff215d"),
      "Name" : "Design Patterns",
      "Price" : 54.93,
      "Category" : "Computers",
      "Author" : "Ralph Johnson"
    }
    {
      "_id" : ObjectId("5bfd996f7b8e48dc15ff215e"),
      "Name" : "Clean Code",
      "Price" : 43.15,
      "Category" : "Computers",
      "Author" : "Robert C. Martin"
    }
    

    Схема добавляет автоматически созданное свойство _id типа ObjectId к каждому документу.

База данных готова к работе. Можно приступить к созданию веб-API ASP.NET Core.

Создание проекта веб-API ASP.NET Core

  1. Выберите Файл>Создать>Проект.

  2. Выберите тип проекта Веб-приложение ASP.NET Core и нажмите кнопку Далее.

  3. Задайте для проекта имя BooksApi и нажмите кнопку Создать.

  4. Выберите целевую платформу .NET Core и ASP.NET Core 3.0. Выберите шаблон проекта API и нажмите кнопку Создать.

  5. Посетите коллекцию NuGet: MongoDB.Driver, чтобы определить последнюю стабильную версию драйвера .NET для MongoDB. В окне Консоль диспетчера пакетов перейдите в корневую папку проекта. Выполните следующую команду, чтобы установить драйвер .NET для MongoDB:

    Install-Package MongoDB.Driver -Version {VERSION}
    

Добавление модели сущности

  1. Добавьте каталог Models в корневую папку проекта.

  2. Добавьте класс Book в каталог Models с помощью такого кода:

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

    В классе выше свойство Id:

    • Требуется для сопоставления объекта среды CLR с коллекцией MongoDB.
    • Помечается с помощью [BsonId] для назначения этого свойства в качестве первичного ключа документа.
    • Помечается с помощью [BsonRepresentation(BsonType.ObjectId)], чтобы разрешить передачу параметра в качестве типа string вместо структуры ObjectId. Mongo обрабатывает преобразование из string в ObjectId.

    Свойство BookName помечено атрибутом [BsonElement]. Значение атрибута Name представляет имя свойства в коллекции MongoDB.

Добавление модели конфигурации

  1. Добавьте в файл appsettings.json следующие значения конфигурации базы данных:

    {
      "BookstoreDatabaseSettings": {
        "BooksCollectionName": "Books",
        "ConnectionString": "mongodb://localhost:27017",
        "DatabaseName": "BookstoreDb"
      },
      "Logging": {
        "IncludeScopes": false,
        "Debug": {
          "LogLevel": {
            "Default": "Warning"
          }
        },
        "Console": {
          "LogLevel": {
            "Default": "Warning"
          }
        }
      }
    }
    
  2. BookstoreDatabaseSettings.cs Добавьте файл в каталог Models со следующим кодом:

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

    Предыдущий класс BookstoreDatabaseSettings используется для хранения значений свойств BookstoreDatabaseSettings файла appsettings.json. Свойства JSON и C# имеют одинаковые имена, что упрощает сопоставление.

  3. Добавьте выделенный ниже код в Startup.ConfigureServices:

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

    В предыдущем коде:

    • Экземпляр конфигурации, к которому привязан раздел BookstoreDatabaseSettings файла appsettings.json, зарегистрирован в контейнере внедрения зависимостей (DI). Например, свойство ConnectionString объекта BookstoreDatabaseSettings заполняется свойством BookstoreDatabaseSettings:ConnectionString в файле appsettings.json.
    • Интерфейс IBookstoreDatabaseSettings регистрируется в DI с использованием времени существования отдельной службы. При внедрении экземпляр интерфейса разрешается в объект BookstoreDatabaseSettings.
  4. Добавьте следующий код в самое начало файла Startup.cs, чтобы разрешить ссылки BookstoreDatabaseSettings и IBookstoreDatabaseSettings:

    using BooksApi.Models;
    

Добавление службы операций CRUD

  1. Добавьте каталог Services в корневую папку проекта.

  2. Добавьте класс BookService в каталог Services с помощью такого кода:

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

    В предыдущем коде экземпляр IBookstoreDatabaseSettings извлекается из DI посредством внедрения конструктора. Таким образом обеспечивается доступ к значениям конфигурации в файле appsettings.json, которые были добавлены в разделе Добавление модели конфигурации.

  3. Добавьте выделенный ниже код в Startup.ConfigureServices:

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

    В предыдущем коде класс BookService регистрируется в DI, чтобы обеспечить поддержку внедрения через конструктор в используемые классы. Время существования отдельной службы — наиболее подходящий вариант, так как BookService имеет прямую зависимость от MongoClient. В соответствии с официальными правилами повторного использования клиента MongoMongoClient следует регистрировать в DI с использованием времени существования отдельной службы.

  4. Добавьте следующий код в самое начало файла Startup.cs, чтобы разрешить ссылку BookService:

    using BooksApi.Services;
    

Класс BookService использует следующие члены MongoDB.Driver для выполнения операций CRUD с базой данных:

  • MongoClient — считывает экземпляр сервера для выполнения операций с базой данных. Конструктор этого класса предоставляет строку подключения MongoDB.

    public BookService(IBookstoreDatabaseSettings settings)
    {
        var client = new MongoClient(settings.ConnectionString);
        var database = client.GetDatabase(settings.DatabaseName);
    
        _books = database.GetCollection<Book>(settings.BooksCollectionName);
    }
    
  • IMongoDatabase — представляет базу данных Mongo для выполнения операций. В этом руководстве используется универсальный метод GetCollection<TDocument>(collection) интерфейса для получения доступа к данным в определенной коллекции. Выполняйте операции CRUD с коллекцией после вызова этого метода. В вызове метода GetCollection<TDocument>(collection):

    • collection представляет имя коллекции;
    • TDocument представляет тип объекта среды CLR, хранящегося в коллекции;

GetCollection<TDocument>(collection) возвращает объект MongoCollection, представляющий коллекцию. В этом руководстве следующие методы вызываются для коллекции:

  • DeleteOne: удаляет один документ, соответствующий заданным критериям поиска.
  • 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

  1. Выполните сборку и запустите приложение.

  2. Перейдите по адресу https://localhost:<port>/api/books, чтобы протестировать не имеющий параметров метод действия Get контроллера. Отобразится такой ответ JSON:

    [
      {
        "id":"5bfd996f7b8e48dc15ff215d",
        "bookName":"Design Patterns",
        "price":54.93,
        "category":"Computers",
        "author":"Ralph Johnson"
      },
      {
        "id":"5bfd996f7b8e48dc15ff215e",
        "bookName":"Clean Code",
        "price":43.15,
        "category":"Computers",
        "author":"Robert C. Martin"
      }
    ]
    
  3. Перейдите по адресу https://localhost:<port>/api/books/{id here}, чтобы протестировать перегруженный метод действия Get контроллера. Отобразится такой ответ JSON:

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

Настройка параметров сериализации JSON

Нужно изменить два параметра для возвращаемых ответов JSON в разделе Тестирование веб-API:

  • Смешанный регистр имен свойств по умолчанию следует изменить в соответствии с регистром Pascal имен свойств объекта CLR.
  • Свойство bookName должно возвращаться как Name.

Чтобы удовлетворить эти требования, внесите следующие изменения:

  1. Компонент Json.NET удален из общей платформы ASP.NET. Добавьте ссылку на пакет для Microsoft.AspNetCore.Mvc.NewtonsoftJson.

  2. В Startup.ConfigureServices вставьте следующий выделенный код в вызов метода AddControllers:

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

    После предыдущего изменения имена свойств в ответе сериализованного JSON веб-API соответствуют именам свойств в типе объекта CLR. Например, свойство Author класса Book сериализуется как Author.

  3. В Models/Book.cs, заметите BookName свойство со следующим [JsonProperty] атрибутом:

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

    Атрибут [JsonProperty] со значением Name представляет имя свойства в сериализованном ответе веб-API в формате JSON.

  4. Добавьте следующий код в самое начало файла Models/Book.cs, чтобы разрешить ссылку на атрибут [JsonProperty]:

    using Newtonsoft.Json;
    
  5. Повторите действия, описанные в разделе Тестирование веб-API. Обратите внимание на различие в именах свойств JSON.

Добавление поддержки аутентификации в веб-API

ASP.NET Core Identity позволяет использовать функцию входа в пользовательском интерфейсе для веб-приложений ASP.NET Core. Чтобы защитить веб-API и одностраничные приложения, используйте один из следующих способов:

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 см. в этих статьях: