Поделиться через


Создание веб-API с помощью ASP.NET Core и MongoDB

Замечание

Это не последняя версия этой статьи. Для текущей версии см. версию .NET 9 этой статьи.

Предупреждение

Эта версия ASP.NET Core больше не поддерживается. Для получения дополнительной информации см. Политику поддержки .NET и .NET Core. Для текущей версии см. версию .NET 9 этой статьи.

Это важно

Эта информация относится к предварительному выпуску продукта, который может быть существенно изменен до его коммерческого выпуска. Корпорация Майкрософт не предоставляет никаких гарантий, явных или подразумеваемых в отношении информации, предоставленной здесь.

Для текущей версии см. версию .NET 9 этой статьи.

Пратик Хандельвал и Скотт Адди

В этом руководстве создается веб-API, который выполняет операции создания, чтения, обновления и удаления (CRUD) в базе данных MongoDB NoSQL.

В этом руководстве вы узнаете, как:

  • Настройка MongoDB
  • Создание базы данных MongoDB
  • Определение коллекции и схемы MongoDB
  • Выполнение операций CRUD MongoDB из веб-API
  • Настройка сериализации JSON

Предпосылки

  • Visual Studio 2022 с рабочей нагрузкой ASP.NET и разработка веб-приложений.

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

Настройка MongoDB

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

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

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

    • macOS/Linux: проверьте каталог, по которому был установлен MongoDB, обычно в /usr/local/mongodb. Добавьте полученный путь к переменной среды mongodbPATH.
    • 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или выполнив следующую команду в командной оболочке:

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

    use BookStore
    

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

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

    db.createCollection('Books')
    

    Отображается следующий результат:

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

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

    Отображается результат, аналогичный следующему:

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

    Замечание

    Результаты ObjectId, показанные в предыдущем примере, не будут совпадать с результатами, показанными в командной оболочке.

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

    db.Books.find().pretty()
    

    Отображается результат, аналогичный следующему:

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

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

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

  1. Перейдите к файлу>нового>проекта.
  2. Выберите тип проекта веб-API ASP.NET Core и нажмите кнопку "Далее".
  3. Назовите проект BookStoreApi и нажмите кнопку "Далее".
  4. В диалоговом окне Дополнительные сведения выполните следующие действия.
  • Убедитесь, что фреймворк — это .NET 9.0 (Стандартная поддержка версии).
  • Убедитесь, что установлен флажок " Использовать контроллеры ".
  • Убедитесь, что установлен флажок для включения поддержки OpenAPI.
  • Выберите Создать.
  1. В окне консоли диспетчера пакетов перейдите в корневой каталог проекта. Выполните следующую команду, чтобы установить драйвер .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 Предыдущий класс используется для хранения значений appsettings.json свойств файлаBookStoreDatabase. Имена свойств JSON и C# называются идентичными, чтобы упростить процесс сопоставления.

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

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

    В приведенном выше коде экземпляр конфигурации, к которому привязан раздел файла appsettings.json, регистрируется в контейнере внедрения зависимостей (DI). Например, свойство BookStoreDatabaseSettings объекта ConnectionString заполняется свойством BookStoreDatabase:ConnectionString в appsettings.json.

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

    using BookStoreApi.Models;
    

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

  1. Добавьте каталог служб в корневой каталог проекта.

  2. BooksService Добавьте класс в каталог Служб со следующим кодом:

    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. В соответствии с официальными рекомендациями по повторному использованию клиента Mongo, MongoClient следует зарегистрировать в DI с временем жизни службы singleton.

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

    using BookStoreApi.Services;
    

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

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

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

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

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

  • DeleteOneAsync: удаляет один документ, соответствующий указанным условиям поиска.
  • Найти<TDocument>: возвращает все документы в коллекции, соответствующие указанным критериям поиска.
  • InsertOneAsync: вставляет предоставленный объект в качестве нового документа в коллекцию.
  • ReplaceOneAsync: заменяет один документ, соответствующий предоставленным условиям поиска, предоставленным объектом.

Добавление контроллера

BooksController Добавьте класс в каталог Controllers со следующим кодом:

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

namespace BookStoreApi.Controllers;

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

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

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

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

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

        return book;
    }

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

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

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

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

        updatedBook.Id = book.Id;

        await _booksService.UpdateAsync(id, updatedBook);

        return NoContent();
    }

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

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

        await _booksService.RemoveAsync(id);

        return NoContent();
    }
}

Предыдущий контроллер веб-API:

  • Использует класс BooksService для выполнения операций CRUD.
  • Содержит методы действий для поддержки запросов GET, POST, PUT и DELETE HTTP.
  • Вызывает CreatedAtAction в методе Create действия для возврата HTTP 201 ответа. Код состояния 201 — это стандартный ответ для метода HTTP POST, который создает новый ресурс на сервере. CreatedAtAction также добавляет заголовок Location в ответ. Заголовок Location задает универсальный код ресурса (URI) только что созданной книги.

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

В разделе «Тестирование веб-API» необходимо изменить два аспекта, касающихся возвращаемых ответов JSON.

  • Имена свойств, оформленные по умолчанию в стиле camelCase, должны быть изменены на оформление в стиле PascalCase в соответствии с именами свойств объекта 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. Например, Book свойство класса Author сериализуется как Author вместо author.

  2. В Models/Book.cs, аннотируйте свойство BookName атрибутом [JsonPropertyName].

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

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

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

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

Тестирование веб-API

В этом руководстве для тестирования API используются обозреватель конечных точек и HTTP-файлы .

  1. Создайте и запустите приложение.

  2. В обозревателе конечных точек щелкните правой кнопкой мыши первую конечную точку /api/books и выберите команду "Создать запрос".

    В файл добавляется следующее содержимое BookStoreApi.http . Если это первый раз, когда создается запрос, файл создается в корневом каталоге проекта.

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

    Номер порта уже должен быть задан для порта, используемого приложением, например https://localhost:56874. Если это не так, вы можете найти номер порта в окне вывода при запуске приложения.

  3. Выберите ссылку "Отправить запрос " над новой GET строкой запроса.

    Запрос GET отправляется приложению, а ответ отображается в области ответа .

  4. Текст ответа показывает результат JSON, содержащий записи книги, аналогичные следующим:

    [
      {
        "Id": "61a6058e6c43f32854e51f51",
        "Name": "Design Patterns",
        "Price": 54.93,
        "Category": "Computers",
        "Author": "Ralph Johnson"
      },
      {
        "Id": "61a6058e6c43f32854e51f52",
        "Name": "Clean Code",
        "Price": 43.15,
        "Category": "Computers",
        "Author": "Robert C. Martin"
      }
    ]
    
  5. Чтобы получить одну книгу, щелкните правой кнопкой мыши /api/books/{id}, params (string id) конечную точку GET в обозревателе конечных точек и выберите команду "Создать запрос".

    К файлу добавляется следующее содержимое BookStoreApi.http :

    @id=string
    GET {{BookStoreApi_HostAddress}}/api/books/{{id}}
    
    ###
    
  6. Замените id переменную одним из идентификаторов, возвращенных из предыдущего запроса, например:

    @id="61a6058e6c43f32854e51f52"
    GET {{BookStoreApi_HostAddress}}/api/books/{{id}}
    
    ###
    
  7. Выберите ссылку "Отправить запрос " над новой GET строкой запроса.

    Запрос GET отправляется приложению, а ответ отображается в области ответа .

  8. Тело ответа содержит JSON, аналогичный следующему:

    {
      "Id": "61a6058e6c43f32854e51f52",
      "Name": "Clean Code",
      "Price": 43.15,
      "Category": "Computers",
      "Author": "Robert C. Martin"
    }
    
  9. Чтобы проверить конечную точку POST, щелкните правой /api/books кнопкой мыши конечную точку POST и выберите команду "Создать запрос".

    В файл добавляется следующее содержимое BookStoreApi.http :

    POST {{BookStoreApi_HostAddress}}/api/books
    Content-Type: application/json
    
    {
      //Book
    }
    
    ###
    
  10. Замените комментарий Book объектом книги в виде текста запроса JSON:

    POST {{BookStoreApi_HostAddress}}/api/books
    Content-Type: application/json
    
     {
       "Name": "The Pragmatic Programmer",
       "Price": 49.99,
       "Category": "Computers",
       "Author": "Andy Hunt"
     }
    
    ###
    
  11. Выберите ссылку "Отправить запрос " над строкой POST запроса.

    Запрос POST отправляется в приложение, а ответ отображается в области ответа . Ответ должен содержать только что созданную книгу с назначенным идентификатором.

  12. Наконец, чтобы удалить книгу, щелкните правой кнопкой мыши /api/books/{id}, params (string id) конечную точку DELETE и выберите "Создать запрос".

    К файлу добавляется следующее содержимое BookStoreApi.http :

    DELETE {{BookStoreApi_HostAddress}}/api/Books/{{id}}
    
    ###
    
  13. Замените id переменную одним из идентификаторов, возвращенных из предыдущего запроса, и нажмите кнопку "Отправить запрос". Рассмотрим пример.

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

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

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

Duende Identity Server — это платформа OpenID Connect и OAuth 2.0 для ASP.NET Core. Duende Identity Server включает следующие функции безопасности:

  • Проверка подлинности как услуга (AaaS)
  • Единый вход и выход (SSO) для нескольких типов приложений
  • Контроль доступа для API
  • Шлюз федерации

Это важно

Компания Duende Software может потребовать оплаты лицензионного сбора за использование Duende Identity Server в производственной среде. Дополнительные сведения см. в статье "Миграция из ASP.NET Core в .NET 5 в .NET 6".

Дополнительные сведения см. в документации по Duende Identity Server (на веб-сайте ПО Duende).

Дополнительные ресурсы

В этом руководстве создается веб-API, который выполняет операции создания, чтения, обновления и удаления (CRUD) в базе данных MongoDB NoSQL.

В этом руководстве вы узнаете, как:

  • Настройка MongoDB
  • Создание базы данных MongoDB
  • Определение коллекции и схемы MongoDB
  • Выполнение операций CRUD MongoDB из веб-API
  • Настройка сериализации JSON

Предпосылки

  • Visual Studio 2022 с рабочей нагрузкой ASP.NET и разработка веб-приложений.

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

Настройка MongoDB

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

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

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

    • macOS/Linux: проверьте каталог, по которому был установлен MongoDB, обычно в /usr/local/mongodb. Добавьте полученный путь к переменной среды mongodbPATH.
    • 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или выполнив следующую команду в командной оболочке:

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

    use BookStore
    

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

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

    db.createCollection('Books')
    

    Отображается следующий результат:

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

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

    Отображается результат, аналогичный следующему:

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

    Замечание

    Результаты ObjectId, показанные в предыдущем примере, не будут совпадать с результатами, показанными в командной оболочке.

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

    db.Books.find().pretty()
    

    Отображается результат, аналогичный следующему:

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

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

Создание проекта веб-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 Предыдущий класс используется для хранения значений appsettings.json свойств файлаBookStoreDatabase. Имена свойств JSON и C# называются идентичными, чтобы упростить процесс сопоставления.

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

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

    В приведенном выше коде экземпляр конфигурации, к которому привязан раздел файла appsettings.json, регистрируется в контейнере внедрения зависимостей (DI). Например, свойство BookStoreDatabaseSettings объекта ConnectionString заполняется свойством BookStoreDatabase:ConnectionString в appsettings.json.

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

    using BookStoreApi.Models;
    

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

  1. Добавьте каталог служб в корневой каталог проекта.

  2. BooksService Добавьте класс в каталог Служб со следующим кодом:

    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. В соответствии с официальными рекомендациями по повторному использованию клиента Mongo, MongoClient следует зарегистрировать в DI с временем жизни службы singleton.

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

    using BookStoreApi.Services;
    

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

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

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

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

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

  • DeleteOneAsync: удаляет один документ, соответствующий указанным условиям поиска.
  • Найти<TDocument>: возвращает все документы в коллекции, соответствующие указанным критериям поиска.
  • InsertOneAsync: вставляет предоставленный объект в качестве нового документа в коллекцию.
  • ReplaceOneAsync: заменяет один документ, соответствующий предоставленным условиям поиска, предоставленным объектом.

Добавление контроллера

BooksController Добавьте класс в каталог Controllers со следующим кодом:

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

namespace BookStoreApi.Controllers;

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

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

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

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

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

        return book;
    }

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

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

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

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

        updatedBook.Id = book.Id;

        await _booksService.UpdateAsync(id, updatedBook);

        return NoContent();
    }

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

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

        await _booksService.RemoveAsync(id);

        return NoContent();
    }
}

Предыдущий контроллер веб-API:

  • Использует класс BooksService для выполнения операций CRUD.
  • Содержит методы действий для поддержки запросов GET, POST, PUT и DELETE HTTP.
  • Вызывает 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

В разделе «Тестирование веб-API» необходимо изменить два аспекта, касающихся возвращаемых ответов JSON.

  • Имена свойств, оформленные по умолчанию в стиле camelCase, должны быть изменены на оформление в стиле PascalCase в соответствии с именами свойств объекта 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. Например, Book свойство класса Author сериализуется как Author вместо author.

  2. В Models/Book.cs, аннотируйте свойство BookName атрибутом [JsonPropertyName].

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

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

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

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

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

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

Duende Identity Server — это платформа OpenID Connect и OAuth 2.0 для ASP.NET Core. Duende Identity Server включает следующие функции безопасности:

  • Проверка подлинности как услуга (AaaS)
  • Единый вход и выход (SSO) для нескольких типов приложений
  • Контроль доступа для API
  • Шлюз федерации

Это важно

Компания Duende Software может потребовать оплаты лицензионного сбора за использование Duende Identity Server в производственной среде. Дополнительные сведения см. в статье "Миграция из ASP.NET Core в .NET 5 в .NET 6".

Дополнительные сведения см. в документации по Duende Identity Server (на веб-сайте ПО Duende).

Дополнительные ресурсы

В этом руководстве создается веб-API, который выполняет операции создания, чтения, обновления и удаления (CRUD) в базе данных MongoDB NoSQL.

В этом руководстве вы узнаете, как:

  • Настройка MongoDB
  • Создание базы данных MongoDB
  • Определение коллекции и схемы MongoDB
  • Выполнение операций CRUD MongoDB из веб-API
  • Настройка сериализации JSON

Предпосылки

  • Visual Studio 2022 с рабочей нагрузкой ASP.NET и разработка веб-приложений.

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

Настройка MongoDB

Включите доступ к MongoDB и оболочке MongoDB из любой точки компьютера разработки.

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

  2. Скачайте оболочку MongoDB и выберите папку для её извлечения. Добавьте полученный путь к переменной среды mongosh.exePATH.

  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или выполнив следующую команду в командной оболочке:

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

    use BookStore
    

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

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

    db.createCollection('Books')
    

    Отображается следующий результат:

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

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

    Отображается результат, аналогичный следующему:

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

    Замечание

    Результаты ObjectId, показанные в предыдущем примере, не будут совпадать с результатами, показанными в командной оболочке.

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

    db.Books.find().pretty()
    

    Отображается результат, аналогичный следующему:

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

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

Создание проекта веб-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 Предыдущий класс используется для хранения значений appsettings.json свойств файлаBookStoreDatabase. Имена свойств JSON и C# называются идентичными, чтобы упростить процесс сопоставления.

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

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

    В приведенном выше коде экземпляр конфигурации, к которому привязан раздел файла appsettings.json, регистрируется в контейнере внедрения зависимостей (DI). Например, свойство BookStoreDatabaseSettings объекта ConnectionString заполняется свойством BookStoreDatabase:ConnectionString в appsettings.json.

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

    using BookStoreApi.Models;
    

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

  1. Добавьте каталог служб в корневой каталог проекта.

  2. BooksService Добавьте класс в каталог Служб со следующим кодом:

    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. В соответствии с официальными рекомендациями по повторному использованию клиента Mongo, MongoClient следует зарегистрировать в DI с временем жизни службы singleton.

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

    using BookStoreApi.Services;
    

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

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

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

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

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

  • DeleteOneAsync: удаляет один документ, соответствующий указанным условиям поиска.
  • Найти<TDocument>: возвращает все документы в коллекции, соответствующие указанным критериям поиска.
  • InsertOneAsync: вставляет предоставленный объект в качестве нового документа в коллекцию.
  • ReplaceOneAsync: заменяет один документ, соответствующий предоставленным условиям поиска, предоставленным объектом.

Добавление контроллера

BooksController Добавьте класс в каталог Controllers со следующим кодом:

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

namespace BookStoreApi.Controllers;

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

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

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

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

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

        return book;
    }

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

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

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

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

        updatedBook.Id = book.Id;

        await _booksService.UpdateAsync(id, updatedBook);

        return NoContent();
    }

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

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

        await _booksService.RemoveAsync(id);

        return NoContent();
    }
}

Предыдущий контроллер веб-API:

  • Использует класс BooksService для выполнения операций CRUD.
  • Содержит методы действий для поддержки запросов GET, POST, PUT и DELETE HTTP.
  • Вызывает 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

В разделе «Тестирование веб-API» необходимо изменить два аспекта, касающихся возвращаемых ответов JSON.

  • Имена свойств, оформленные по умолчанию в стиле camelCase, должны быть изменены на оформление в стиле PascalCase в соответствии с именами свойств объекта 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. Например, Book свойство класса Author сериализуется как Author вместо author.

  2. В Models/Book.cs, аннотируйте свойство BookName атрибутом [JsonPropertyName].

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

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

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

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

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

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

Duende Identity Server — это платформа OpenID Connect и OAuth 2.0 для ASP.NET Core. Duende Identity Server включает следующие функции безопасности:

  • Проверка подлинности как услуга (AaaS)
  • Единый вход и выход (SSO) для нескольких типов приложений
  • Контроль доступа для API
  • Шлюз федерации

Это важно

Компания Duende Software может потребовать оплаты лицензионного сбора за использование Duende Identity Server в производственной среде. Дополнительные сведения см. в статье "Миграция из ASP.NET Core в .NET 5 в .NET 6".

Дополнительные сведения см. в документации по Duende Identity Server (на веб-сайте ПО Duende).

Дополнительные ресурсы

В этом руководстве создается веб-API, который выполняет операции создания, чтения, обновления и удаления (CRUD) в базе данных MongoDB NoSQL.

В этом руководстве вы узнаете, как:

  • Настройка MongoDB
  • Создание базы данных MongoDB
  • Определение коллекции и схемы MongoDB
  • Выполнение операций CRUD MongoDB из веб-API
  • Настройка сериализации JSON

Предпосылки

Настройка MongoDB

Включите доступ к MongoDB и оболочке MongoDB из любой точки компьютера разработки.

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

  2. Скачайте оболочку MongoDB и выберите папку для её извлечения. Добавьте полученный путь к переменной среды mongosh.exePATH.

  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или выполнив следующую команду в командной оболочке:

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

    use BookStore
    

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

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

    db.createCollection('Books')
    

    Отображается следующий результат:

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

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

    Отображается результат, аналогичный следующему:

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

    Замечание

    Результаты ObjectId, показанные в предыдущем примере, не будут совпадать с результатами, показанными в командной оболочке.

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

    db.Books.find().pretty()
    

    Отображается результат, аналогичный следующему:

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

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

Создание проекта веб-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 Предыдущий класс используется для хранения значений appsettings.json свойств файлаBookStoreDatabase. Имена свойств JSON и C# называются идентичными, чтобы упростить процесс сопоставления.

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

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

    В приведенном выше коде экземпляр конфигурации, к которому привязан раздел файла appsettings.json, регистрируется в контейнере внедрения зависимостей (DI). Например, свойство BookStoreDatabaseSettings объекта ConnectionString заполняется свойством BookStoreDatabase:ConnectionString в appsettings.json.

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

    using BookStoreApi.Models;
    

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

  1. Добавьте каталог служб в корневой каталог проекта.

  2. BooksService Добавьте класс в каталог Служб со следующим кодом:

    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. В соответствии с официальными рекомендациями по повторному использованию клиента Mongo, MongoClient следует зарегистрировать в DI с временем жизни службы singleton.

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

    using BookStoreApi.Services;
    

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

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

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

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

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

  • DeleteOneAsync: удаляет один документ, соответствующий указанным условиям поиска.
  • Найти<TDocument>: возвращает все документы в коллекции, соответствующие указанным критериям поиска.
  • InsertOneAsync: вставляет предоставленный объект в качестве нового документа в коллекцию.
  • ReplaceOneAsync: заменяет один документ, соответствующий предоставленным условиям поиска, предоставленным объектом.

Добавление контроллера

BooksController Добавьте класс в каталог Controllers со следующим кодом:

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

namespace BookStoreApi.Controllers;

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

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

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

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

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

        return book;
    }

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

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

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

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

        updatedBook.Id = book.Id;

        await _booksService.UpdateAsync(id, updatedBook);

        return NoContent();
    }

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

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

        await _booksService.RemoveAsync(id);

        return NoContent();
    }
}

Предыдущий контроллер веб-API:

  • Использует класс BooksService для выполнения операций CRUD.
  • Содержит методы действий для поддержки запросов GET, POST, PUT и DELETE HTTP.
  • Вызывает 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

В разделе «Тестирование веб-API» необходимо изменить два аспекта, касающихся возвращаемых ответов JSON.

  • Имена свойств, оформленные по умолчанию в стиле camelCase, должны быть изменены на оформление в стиле PascalCase в соответствии с именами свойств объекта 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. Например, Book свойство класса Author сериализуется как Author вместо author.

  2. В Models/Book.cs, аннотируйте свойство BookName атрибутом [JsonPropertyName].

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

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

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

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

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

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

Duende Identity Server — это платформа OpenID Connect и OAuth 2.0 для ASP.NET Core. Duende Identity Server включает следующие функции безопасности:

  • Проверка подлинности как услуга (AaaS)
  • Единый вход и выход (SSO) для нескольких типов приложений
  • Контроль доступа для API
  • Шлюз федерации

Это важно

Компания Duende Software может потребовать оплаты лицензионного сбора за использование Duende Identity Server в производственной среде. Дополнительные сведения см. в статье "Миграция из ASP.NET Core в .NET 5 в .NET 6".

Дополнительные сведения см. в документации по Duende Identity Server (на веб-сайте ПО Duende).

Дополнительные ресурсы

В этом руководстве создается веб-API, который выполняет операции создания, чтения, обновления и удаления (CRUD) в базе данных MongoDB NoSQL.

В этом руководстве вы узнаете, как:

  • Настройка 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 Web Application и нажмите кнопку "Далее".

  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 Предыдущий класс используется для хранения значений appsettings.json свойств файлаBookstoreDatabaseSettings. Имена свойств JSON и C# называются идентичными, чтобы упростить процесс сопоставления.

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

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

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

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

    using BooksApi.Models;
    

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

  1. Добавьте каталог служб в корневой каталог проекта.

  2. BookService Добавьте класс в каталог Служб со следующим кодом:

    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. В соответствии с официальными рекомендациями по повторному использованию клиента Mongo, MongoClient следует зарегистрировать в DI с временем жизни службы singleton.

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

    using BooksApi.Services;
    

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

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

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

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

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

  • DeleteOne: удаляет один документ, соответствующий заданным критериям поиска.
  • Найти<TDocument>: возвращает все документы в коллекции, соответствующие указанным критериям поиска.
  • InsertOne: вставляет предоставленный объект в качестве нового документа в коллекцию.
  • ReplaceOne: заменяет один документ, соответствующий предоставленным условиям поиска, предоставленным объектом.

Добавление контроллера

BooksController Добавьте класс в каталог Controllers со следующим кодом:

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

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

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

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

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

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

            return book;
        }

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

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

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

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

            _bookService.Update(id, bookIn);

            return NoContent();
        }

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

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

            _bookService.Remove(id);

            return NoContent();
        }
    }
}

Предыдущий контроллер веб-API:

  • Использует класс BookService для выполнения операций CRUD.
  • Содержит методы действий для поддержки запросов GET, POST, PUT и DELETE HTTP.
  • Вызывает 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

В разделе «Тестирование веб-API» необходимо изменить два аспекта, касающихся возвращаемых ответов JSON.

  • Имена свойств, оформленные по умолчанию в стиле camelCase, должны быть изменены на оформление в стиле PascalCase в соответствии с именами свойств объекта 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. Например, свойство Book класса Author сериализуется как Author.

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

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

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

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

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

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

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

Duende IdentityServer — это платформа OpenID Connect и OAuth 2.0 для ASP.NET Core. Duende IdentityServer включает следующие функции безопасности:

  • Проверка подлинности как услуга (AaaS)
  • Единый вход и выход (SSO) для нескольких типов приложений
  • Контроль доступа для API
  • Шлюз федерации

Дополнительные сведения см. в разделе "Обзор Duende IdentityServer".

Дополнительные сведения о других поставщиках проверки подлинности см. в разделе "Параметры проверки подлинности Community OSS" для ASP.NET Core

Дальнейшие шаги

Дополнительные сведения о создании веб-API ASP.NET Core см. в следующих ресурсах: