Compartilhar via


Criar uma API Web com o ASP.NET Core e o MongoDB

Observação

Esta não é a versão mais recente deste artigo. Para informações sobre a versão vigente, confira a Versão do .NET 8 deste artigo.

Importante

Essas informações relacionam-se ao produto de pré-lançamento, que poderá ser substancialmente modificado antes do lançamento comercial. A Microsoft não oferece nenhuma garantia, explícita ou implícita, quanto às informações fornecidas aqui.

Para informações sobre a versão vigente, confira a Versão do .NET 8 deste artigo.

Por Pratik Khandelwal e Scott Addie

Este tutorial cria uma API Web que executa as operações CRUD (criar, ler, atualizar e excluir) em um banco de dados NoSQL do MongoDB.

Neste tutorial, você aprenderá como:

  • Configurar o MongoDB
  • Criar um banco de dados do MongoDB
  • Definir uma coleção e um esquema do MongoDB
  • Executar operações CRUD do MongoDB a partir de uma API Web
  • Personalizar a serialização JSON

Pré-requisitos

Configurar o MongoDB

Habilite o acesso ao MongoDB e ao MongoDB Shell de qualquer lugar na máquina de desenvolvimento (Windows/Linux/macOS):

  1. Baixe e instale o MongoDB Shell:

    • macOS/Linux: Escolha um diretório para extrair o Shell do MongoDB. Adicione o caminho resultante para mongosh à variável de ambiente PATH.
    • Windows: MongoDB Shell (mongosh.exe) está instalado em C\Users<user>\AppData\Local\Programs\mongosh. Adicione o caminho resultante para mongosh.exe à variável de ambiente PATH.
  2. Baixe e instale o MongoDB:

    • macOS/Linux: Verifique o diretório em que o MongoDB foi instalado, geralmente em /usr/local/mongodb. Adicione o caminho resultante para mongodb à variável de ambiente PATH.
    • Windows: O MongoDB é instalado em C:\Program Files\MongoDB por padrão. Adicione C:\Arquivos de Programas\MongoDB\Server<número_de_versão>\bin à variável de ambiente PATH.
  3. Escolha um diretório de armazenamento de dados: Selecione um diretório em sua máquina de desenvolvimento para armazenar dados. Crie o diretório se não houver um. O MongoDB Shell não cria novos diretórios:

    • macOS/Linux: Por exemplo, /usr/local/var/mongodb.
    • Windows: Por exemplo, C:\\BooksData.
  4. No shell de comando do sistema operacional (não no Shell do MongoDB), use o comando a seguir para se conectar ao MongoDB na porta padrão 27017. Substitua <data_directory_path> pelo diretório escolhido na etapa anterior.

    mongod --dbpath <data_directory_path>
    

Use o Shell do MongoDB instalado nas etapas a seguir para criar um banco de dados, criar coleções e armazenar documentos. Para obter mais informações sobre comandos do Shell do MongoDB, consulte mongosh.

  1. Abra uma instância do shell de comando do MongoDB iniciando mongosh.exe.

  2. No shell de comando, conecte-se ao banco de dados de teste padrão executando o seguinte comando:

    mongosh
    
  3. Execute o seguinte comando no shell de comando:

    use BookStore
    

    Um banco de dados chamado BookstoreDb será criado se ele já não existir. Se o banco de dados existir, a conexão dele será aberta para transações.

  4. Crie uma coleção Books usando o seguinte comando:

    db.createCollection('Books')
    

    O seguinte resultado é exibido:

    { "ok" : 1 }
    
  5. Defina um esquema para a coleção Books e insira dois documentos usando o seguinte comando:

    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" }])
    

    Um resultado semelhante ao apresentado a seguir será exibido:

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

    Observação

    Os ObjectIds mostrados no resultado anterior não corresponderão aos mostrados no shell de comando.

  6. Visualize os documentos no banco de dados usando o seguinte comando:

    db.Books.find().pretty()
    

    Um resultado semelhante ao apresentado a seguir será exibido:

    {
         "_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"
     }
    

    O esquema adiciona uma propriedade _id gerada automaticamente do tipo ObjectId para cada documento.

Criar o projeto da API Web do ASP.NET Core

  1. Acesse Arquivo>Novo>Projeto.

  2. Selecione o tipo do projeto da API Web do ASP.NET Core e, em seguida, Avançar.

  3. Nomeie o projeto como BookStoreApi e clique em Avançar.

  4. Selecione a estrutura .NET 8.0 (suporte de longo prazo) e escolha Criar.

  5. Na janela Console do Gerenciador de Pacotes, navegue até a raiz do projeto. Execute o seguinte comando para instalar o driver .NET para MongoDB:

    Install-Package MongoDB.Driver
    

Adicionar um modelo de entidade

  1. Adicione um diretório Modelos à raiz do projeto.

  2. Adicione uma classe Book ao diretório Modelos com o seguinte código:

    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!;
    }
    

    Na classe anterior, a propriedade Id é:

    • Necessária para mapear o objeto CLR (Common Language Runtime) para a coleção do MongoDB.
    • Anotada com [BsonId] para designar essa propriedade como a chave primária do documento.
    • Anotada com [BsonRepresentation(BsonType.ObjectId)] para permitir a passagem do parâmetro como tipo string, em vez de uma estrutura ObjectId. O Mongo processa a conversão de string para ObjectId.

    A propriedade BookName é anotada com o atributo [BsonElement]. O valor do atributo de Name representa o nome da propriedade da coleção do MongoDB.

Adicionar um modelo de configuração

  1. Adicione os seguintes valores de configuração de banco de dados a appsettings.json:

    {
        "BookStoreDatabase": {
            "ConnectionString": "mongodb://localhost:27017",
            "DatabaseName": "BookStore",
            "BooksCollectionName": "Books"
        },
        "Logging": {
            "LogLevel": {
                "Default": "Information",
                "Microsoft.AspNetCore": "Warning"
            }
        },
        "AllowedHosts": "*"
    }
    
  2. Adicione uma classe BookStoreDatabaseSettings ao diretório Modelos com o seguinte código:

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

    A classe anterior BookStoreDatabaseSettings é usada para armazenar os valores de propriedade BookStoreDatabase do arquivo appsettings.json. Os nomes de propriedade JSON e C# são nomeados de forma idêntica para facilitar o processo de mapeamento.

  3. Adicione o código realçado a seguir a Program.cs:

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

    No código anterior, a instância de configuração à qual a seção BookStoreDatabase do arquivo appsettings.json é registrada no contêiner de DI (Injeção de Dependência). Por exemplo, a propriedade ConnectionString de um objeto BookStoreDatabaseSettings é populada com a propriedade BookStoreDatabase:ConnectionString no appsettings.json.

  4. Adicione o seguinte código na parte superior do Program.cs para resolver a referência BookStoreDatabaseSettings:

    using BookStoreApi.Models;
    

Adicionar um serviço de operações CRUD

  1. Adicione um diretório Serviços à raiz do projeto.

  2. Adicione uma classe BooksService ao diretório Serviços com o seguinte código:

    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);
    }
    

    No código anterior, uma instância BookStoreDatabaseSettings é recuperada da DI por meio da injeção de construtor. Essa técnica fornece acesso para os valores de configuração do appsettings.json que foram adicionados na seção Adicionar um modelo de configuração.

  3. Adicione o código realçado a seguir a Program.cs:

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

    No código anterior, a classe BooksService é registrada com a DI para dar suporte à injeção de construtor nas classes consumidoras. O tempo de vida do serviço singleton é mais apropriado porque BooksService usa uma dependência direta de MongoClient. De acordo com as Diretrizes oficiais de reutilização do cliente Mongo, o MongoClient deve ser registrado na DI com um tempo de vida do serviço singleton.

  4. Adicione o seguinte código na parte superior do Program.cs para resolver a referência BooksService:

    using BookStoreApi.Services;
    

A classe BooksService usa os seguintes membros MongoDB.Driver para executar operações CRUD em relação ao banco de dados:

  • MongoClient: lê a instância do servidor para executar operações de banco de dados. O construtor dessa classe é fornecido na cadeia de conexão do 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: representa o banco de dados Mongo para execução de operações. Este tutorial usa o método GetCollection<TDocument>(coleção) genérico na interface para obter acesso aos dados em uma coleção específica. Execute operações CRUD em relação à coleção depois que esse método for chamado. Na chamada de método GetCollection<TDocument>(collection):

    • collection representa o nome da coleção.
    • TDocument representa o tipo de objeto CLR armazenado na coleção.

GetCollection<TDocument>(collection) retorna um objeto MongoCollection que representa a coleção. Neste tutorial, os seguintes métodos são invocados na coleção:

  • DeleteOneAsync: exclui um único documento que corresponde aos critérios de pesquisa fornecidos.
  • Encontrar<TDocument>: retorna todos os documentos na coleção que correspondem aos critérios de pesquisa fornecidos.
  • InsertOneAsync: insere o objeto fornecido como um novo documento na coleção.
  • ReplaceOneAsync: substitui o único documento que corresponde aos critérios de pesquisa fornecidos com o objeto fornecido.

Adicionar um controlador

Adicione uma classe BooksController ao diretório Controladores com o seguinte código:

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();
    }
}

O controlador da API Web anterior:

  • Usa a classe BooksService para executar operações CRUD.
  • Contém métodos de ação para dar suporte a solicitações GET, POST, PUT e DELETE HTTP.
  • Chama o CreatedAtAction no método de ação Create para retornar uma resposta HTTP 201. O código de status 201 é a resposta padrão para um método HTTP POST que cria um recurso no servidor. CreatedAtAction também adiciona um cabeçalho Location à resposta. O cabeçalho Location especifica o URI do livro recém-criado.

Testar a API Web

  1. Compile e execute o aplicativo.

  2. Navegue até https://localhost:<port>/api/books, onde <port> é o número da porta atribuído automaticamente para o aplicativo, para testar o método de ação Get sem parâmetros do controlador, selecione Experimente>Executar. Uma resposta JSON semelhante à apresentada a seguir será exibida:

    [
      {
        "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. Navegue até https://localhost:<port>/api/books/{id here} para testar o método de ação Get sobrecarregado do controlador. Uma resposta JSON semelhante à apresentada a seguir será exibida:

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

Configurar opções de serialização JSON

Há dois detalhes alterar sobre as respostas JSON retornadas na seção Testar a API Web:

  • O uso de maiúsculas e minúsculas padrão dos nomes da propriedade deve ser alterado para corresponder ao uso de maiúsculas e minúsculas Pascal dos nomes de propriedade do objeto CLR.
  • A propriedade bookName deve ser retornada como Name.

Para cumprir os requisitos anteriores, faça as seguintes alterações:

  1. Em Program.cs, encadeie o seguinte código realçado para a chamada de método 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);
    

    Com a alteração anterior, os nomes de propriedade na resposta JSON serializada da API Web correspondem aos respectivos nomes de propriedade no tipo de objeto CLR. Por exemplo, a propriedade Author da classe Book é serializada como Author ao invés de author.

  2. No Models/Book.cs, anote a propriedade BookName com o atributo [JsonPropertyName]:

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

    O valor do atributo [JsonPropertyName] de Name representa o nome da propriedade da resposta JSON serializada da API Web.

  3. Adicione o seguinte código na parte superior do Models/Book.cs para resolver a referência [JsonProperty] do atributo:

    using System.Text.Json.Serialization;
    
  4. Repita as etapas definidas na seção Testar a API Web. Observe a diferença nos nomes de propriedade JSON.

Adicionar suporte de autenticação a uma API Web

O ASP.NET Core Identity adiciona a funcionalidade de logon da interface do usuário aos aplicativos Web do ASP.NET Core. Para proteger APIs Web e SPAs, use uma das seguintes opções:

O Duende Identity Server é uma estrutura do OpenID Connect e OAuth 2.0 para ASP.NET Core. O Duende Identity Server habilita os seguintes recursos de segurança:

  • AaaS (autenticação como serviço)
  • SSO (logon único) em vários tipos de aplicativo
  • Controle de acesso para APIs
  • Federation Gateway

Importante

O Software Duende pode exigir que você pague uma taxa de licença pelo uso de produção do Duende Identity Server. Para obter mais informações, consulte Migrar do ASP.NET Core 5.0 para o 6.0.

Para obter mais informações, confira a documentação do Duende Identity Server (site da Duende Software).

Recursos adicionais

Este tutorial cria uma API Web que executa as operações CRUD (criar, ler, atualizar e excluir) em um banco de dados NoSQL do MongoDB.

Neste tutorial, você aprenderá como:

  • Configurar o MongoDB
  • Criar um banco de dados do MongoDB
  • Definir uma coleção e um esquema do MongoDB
  • Executar operações CRUD do MongoDB a partir de uma API Web
  • Personalizar a serialização JSON

Pré-requisitos

Configurar o MongoDB

Habilite o acesso ao Shell do MongoDB e do Mongo DB de qualquer lugar no computador de desenvolvimento:

  1. Se você usar o Windows, o MongoDB será instalado em C:\Arquivos de Programas\MongoDB por padrão. Adicione C:\Arquivos de Programas\MongoDB\Server<número_de_versão>>\bin à variável de ambiente PATH.

  2. Baixe o Shell do MongoDB e escolha um diretório para o qual extraí-lo. Adicione o caminho resultante para mongosh.exe à variável de ambiente PATH.

  3. Escolha um diretório no seu computador de desenvolvimento para armazenar os dados. Por exemplo, C:\BooksData no Windows. Crie o diretório se não houver um. O Shell do mongo não cria novos diretórios.

  4. No shell de comando do sistema operacional (não no Shell do MongoDB), use o comando a seguir para se conectar ao MongoDB na porta padrão 27017. Substitua <data_directory_path> pelo diretório escolhido na etapa anterior.

    mongod --dbpath <data_directory_path>
    

Use o Shell do MongoDB instalado nas etapas a seguir para criar um banco de dados, criar coleções e armazenar documentos. Para obter mais informações sobre comandos do Shell do MongoDB, consulte mongosh.

  1. Abra uma instância do shell de comando do MongoDB iniciando mongosh.exe.

  2. Conecte-se ao banco de dados de testes padrão executando o seguinte comando no shell de comando:

    mongosh
    
  3. Execute o seguinte comando no shell de comando:

    use BookStore
    

    Um banco de dados chamado BookstoreDb será criado se ele já não existir. Se o banco de dados existir, a conexão dele será aberta para transações.

  4. Crie uma coleção Books usando o seguinte comando:

    db.createCollection('Books')
    

    O seguinte resultado é exibido:

    { "ok" : 1 }
    
  5. Defina um esquema para a coleção Books e insira dois documentos usando o seguinte comando:

    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" }])
    

    Um resultado semelhante ao apresentado a seguir será exibido:

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

    Observação

    Os ObjectIds mostrados no resultado anterior não corresponderão aos mostrados no shell de comando.

  6. Visualize os documentos no banco de dados usando o seguinte comando:

    db.Books.find().pretty()
    

    Um resultado semelhante ao apresentado a seguir será exibido:

    {
         "_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"
     }
    

    O esquema adiciona uma propriedade _id gerada automaticamente do tipo ObjectId para cada documento.

Criar o projeto da API Web do ASP.NET Core

  1. Acesse Arquivo>Novo>Projeto.

  2. Selecione o tipo do projeto da API Web do ASP.NET Core e, em seguida, Avançar.

  3. Nomeie o projeto como BookStoreApi e clique em Avançar.

  4. Selecione a estrutura .NET 7.0 (Standard Term Support) e selecione Criar.

  5. No menu Ferramentas selecione Gerenciador de Pacotes NuGet>Console do Gerenciador de Pacotes.

  6. Na janela Console do Gerenciador de Pacotes, navegue até a raiz do projeto. Execute o seguinte comando para instalar o driver .NET para MongoDB:

    Install-Package MongoDB.Driver
    

Adicionar um modelo de entidade

  1. Adicione um diretório Modelos à raiz do projeto.

  2. Adicione uma classe Book ao diretório Modelos com o seguinte código:

    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!;
    }
    

    Na classe anterior, a propriedade Id é:

    • Necessária para mapear o objeto CLR (Common Language Runtime) para a coleção do MongoDB.
    • Anotada com [BsonId] para designar essa propriedade como a chave primária do documento.
    • Anotada com [BsonRepresentation(BsonType.ObjectId)] para permitir a passagem do parâmetro como tipo string, em vez de uma estrutura ObjectId. O Mongo processa a conversão de string para ObjectId.

    A propriedade BookName é anotada com o atributo [BsonElement]. O valor do atributo de Name representa o nome da propriedade da coleção do MongoDB.

Adicionar um modelo de configuração

  1. Adicione os seguintes valores de configuração de banco de dados a appsettings.json:

    {
      "BookStoreDatabase": {
        "ConnectionString": "mongodb://localhost:27017",
        "DatabaseName": "BookStore",
        "BooksCollectionName": "Books"
      },
      "Logging": {
        "LogLevel": {
          "Default": "Information",
          "Microsoft.AspNetCore": "Warning"
        }
      },
      "AllowedHosts": "*"
    }
    
  2. Adicione uma classe BookStoreDatabaseSettings ao diretório Modelos com o seguinte código:

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

    A classe anterior BookStoreDatabaseSettings é usada para armazenar os valores de propriedade BookStoreDatabase do arquivo appsettings.json. Os nomes de propriedade JSON e C# são nomeados de forma idêntica para facilitar o processo de mapeamento.

  3. Adicione o código realçado a seguir a Program.cs:

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

    No código anterior, a instância de configuração à qual a seção BookStoreDatabase do arquivo appsettings.json é registrada no contêiner de DI (Injeção de Dependência). Por exemplo, a propriedade ConnectionString de um objeto BookStoreDatabaseSettings é populada com a propriedade BookStoreDatabase:ConnectionString no appsettings.json.

  4. Adicione o seguinte código na parte superior do Program.cs para resolver a referência BookStoreDatabaseSettings:

    using BookStoreApi.Models;
    

Adicionar um serviço de operações CRUD

  1. Adicione um diretório Serviços à raiz do projeto.

  2. Adicione uma classe BooksService ao diretório Serviços com o seguinte código:

    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);
    }
    

    No código anterior, uma instância BookStoreDatabaseSettings é recuperada da DI por meio da injeção de construtor. Essa técnica fornece acesso para os valores de configuração do appsettings.json que foram adicionados na seção Adicionar um modelo de configuração.

  3. Adicione o código realçado a seguir a Program.cs:

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

    No código anterior, a classe BooksService é registrada com a DI para dar suporte à injeção de construtor nas classes consumidoras. O tempo de vida do serviço singleton é mais apropriado porque BooksService usa uma dependência direta de MongoClient. De acordo com as Diretrizes oficiais de reutilização do cliente Mongo, o MongoClient deve ser registrado na DI com um tempo de vida do serviço singleton.

  4. Adicione o seguinte código na parte superior do Program.cs para resolver a referência BooksService:

    using BookStoreApi.Services;
    

A classe BooksService usa os seguintes membros MongoDB.Driver para executar operações CRUD em relação ao banco de dados:

  • MongoClient: lê a instância do servidor para executar operações de banco de dados. O construtor dessa classe é fornecido na cadeia de conexão do 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: representa o banco de dados Mongo para execução de operações. Este tutorial usa o método GetCollection<TDocument>(coleção) genérico na interface para obter acesso aos dados em uma coleção específica. Execute operações CRUD em relação à coleção depois que esse método for chamado. Na chamada de método GetCollection<TDocument>(collection):

    • collection representa o nome da coleção.
    • TDocument representa o tipo de objeto CLR armazenado na coleção.

GetCollection<TDocument>(collection) retorna um objeto MongoCollection que representa a coleção. Neste tutorial, os seguintes métodos são invocados na coleção:

  • DeleteOneAsync: exclui um único documento que corresponde aos critérios de pesquisa fornecidos.
  • Encontrar<TDocument>: retorna todos os documentos na coleção que correspondem aos critérios de pesquisa fornecidos.
  • InsertOneAsync: insere o objeto fornecido como um novo documento na coleção.
  • ReplaceOneAsync: substitui o único documento que corresponde aos critérios de pesquisa fornecidos com o objeto fornecido.

Adicionar um controlador

Adicione uma classe BooksController ao diretório Controladores com o seguinte código:

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();
    }
}

O controlador da API Web anterior:

  • Usa a classe BooksService para executar operações CRUD.
  • Contém métodos de ação para dar suporte a solicitações GET, POST, PUT e DELETE HTTP.
  • Chama o CreatedAtAction no método de ação Create para retornar uma resposta HTTP 201. O código de status 201 é a resposta padrão para um método HTTP POST que cria um recurso no servidor. CreatedAtAction também adiciona um cabeçalho Location à resposta. O cabeçalho Location especifica o URI do livro recém-criado.

Testar a API Web

  1. Compile e execute o aplicativo.

  2. Navegue até https://localhost:<port>/api/books, onde <port> é o número da porta atribuído automaticamente para o aplicativo, para testar o método de ação Get sem parâmetros do controlador. Uma resposta JSON semelhante à apresentada a seguir será exibida:

    [
      {
        "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. Navegue até https://localhost:<port>/api/books/{id here} para testar o método de ação Get sobrecarregado do controlador. Uma resposta JSON semelhante à apresentada a seguir será exibida:

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

Configurar opções de serialização JSON

Há dois detalhes alterar sobre as respostas JSON retornadas na seção Testar a API Web:

  • O uso de maiúsculas e minúsculas padrão dos nomes da propriedade deve ser alterado para corresponder ao uso de maiúsculas e minúsculas Pascal dos nomes de propriedade do objeto CLR.
  • A propriedade bookName deve ser retornada como Name.

Para cumprir os requisitos anteriores, faça as seguintes alterações:

  1. Em Program.cs, encadeie o seguinte código realçado para a chamada de método 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);
    

    Com a alteração anterior, os nomes de propriedade na resposta JSON serializada da API Web correspondem aos respectivos nomes de propriedade no tipo de objeto CLR. Por exemplo, a propriedade Author da classe Book é serializada como Author ao invés de author.

  2. No Models/Book.cs, anote a propriedade BookName com o atributo [JsonPropertyName]:

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

    O valor do atributo [JsonPropertyName] de Name representa o nome da propriedade da resposta JSON serializada da API Web.

  3. Adicione o seguinte código na parte superior do Models/Book.cs para resolver a referência [JsonProperty] do atributo:

    using System.Text.Json.Serialization;
    
  4. Repita as etapas definidas na seção Testar a API Web. Observe a diferença nos nomes de propriedade JSON.

Adicionar suporte de autenticação a uma API Web

O ASP.NET Core Identity adiciona a funcionalidade de logon da interface do usuário aos aplicativos Web do ASP.NET Core. Para proteger APIs Web e SPAs, use uma das seguintes opções:

O Duende Identity Server é uma estrutura do OpenID Connect e OAuth 2.0 para ASP.NET Core. O Duende Identity Server habilita os seguintes recursos de segurança:

  • AaaS (autenticação como serviço)
  • SSO (logon único) em vários tipos de aplicativo
  • Controle de acesso para APIs
  • Federation Gateway

Importante

O Software Duende pode exigir que você pague uma taxa de licença pelo uso de produção do Duende Identity Server. Para obter mais informações, consulte Migrar do ASP.NET Core 5.0 para o 6.0.

Para obter mais informações, confira a documentação do Duende Identity Server (site da Duende Software).

Recursos adicionais

Este tutorial cria uma API Web que executa as operações CRUD (criar, ler, atualizar e excluir) em um banco de dados NoSQL do MongoDB.

Neste tutorial, você aprenderá como:

  • Configurar o MongoDB
  • Criar um banco de dados do MongoDB
  • Definir uma coleção e um esquema do MongoDB
  • Executar operações CRUD do MongoDB a partir de uma API Web
  • Personalizar a serialização JSON

Pré-requisitos

Configurar o MongoDB

Habilite o acesso ao Shell do MongoDB e do Mongo DB de qualquer lugar no computador de desenvolvimento:

  1. Se você usar o Windows, o MongoDB será instalado em C:\Arquivos de Programas\MongoDB por padrão. Adicione C:\Arquivos de Programas\MongoDB\Server<número_de_versão>>\bin à variável de ambiente PATH.

  2. Baixe o Shell do MongoDB e escolha um diretório para o qual extraí-lo. Adicione o caminho resultante para mongosh.exe à variável de ambiente PATH.

  3. Escolha um diretório no seu computador de desenvolvimento para armazenar os dados. Por exemplo, C:\BooksData no Windows. Crie o diretório se não houver um. O Shell do mongo não cria novos diretórios.

  4. No shell de comando do sistema operacional (não no Shell do MongoDB), use o comando a seguir para se conectar ao MongoDB na porta padrão 27017. Substitua <data_directory_path> pelo diretório escolhido na etapa anterior.

    mongod --dbpath <data_directory_path>
    

Use o Shell do MongoDB instalado nas etapas a seguir para criar um banco de dados, criar coleções e armazenar documentos. Para obter mais informações sobre comandos do Shell do MongoDB, consulte mongosh.

  1. Abra uma instância do shell de comando do MongoDB iniciando mongosh.exe.

  2. Conecte-se ao banco de dados de testes padrão executando o seguinte comando no shell de comando:

    mongosh
    
  3. Execute o seguinte comando no shell de comando:

    use BookStore
    

    Um banco de dados chamado BookstoreDb será criado se ele já não existir. Se o banco de dados existir, a conexão dele será aberta para transações.

  4. Crie uma coleção Books usando o seguinte comando:

    db.createCollection('Books')
    

    O seguinte resultado é exibido:

    { "ok" : 1 }
    
  5. Defina um esquema para a coleção Books e insira dois documentos usando o seguinte comando:

    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" }])
    

    Um resultado semelhante ao apresentado a seguir será exibido:

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

    Observação

    Os ObjectIds mostrados no resultado anterior não corresponderão aos mostrados no shell de comando.

  6. Visualize os documentos no banco de dados usando o seguinte comando:

    db.Books.find().pretty()
    

    Um resultado semelhante ao apresentado a seguir será exibido:

    {
         "_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"
     }
    

    O esquema adiciona uma propriedade _id gerada automaticamente do tipo ObjectId para cada documento.

Criar o projeto da API Web do ASP.NET Core

  1. Acesse Arquivo>Novo>Projeto.

  2. Selecione o tipo do projeto da API Web do ASP.NET Core e, em seguida, Avançar.

  3. Nomeie o projeto como BookStoreApi e clique em Avançar.

  4. Selecione a estrutura .NET 6.0 (suporte de longo prazo) e selecione Criar.

  5. Na janela Console do Gerenciador de Pacotes, navegue até a raiz do projeto. Execute o seguinte comando para instalar o driver .NET para MongoDB:

    Install-Package MongoDB.Driver
    

Adicionar um modelo de entidade

  1. Adicione um diretório Modelos à raiz do projeto.

  2. Adicione uma classe Book ao diretório Modelos com o seguinte código:

    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!;
    }
    

    Na classe anterior, a propriedade Id é:

    • Necessária para mapear o objeto CLR (Common Language Runtime) para a coleção do MongoDB.
    • Anotada com [BsonId] para designar essa propriedade como a chave primária do documento.
    • Anotada com [BsonRepresentation(BsonType.ObjectId)] para permitir a passagem do parâmetro como tipo string, em vez de uma estrutura ObjectId. O Mongo processa a conversão de string para ObjectId.

    A propriedade BookName é anotada com o atributo [BsonElement]. O valor do atributo de Name representa o nome da propriedade da coleção do MongoDB.

Adicionar um modelo de configuração

  1. Adicione os seguintes valores de configuração de banco de dados a appsettings.json:

    {
        "BookStoreDatabase": {
            "ConnectionString": "mongodb://localhost:27017",
            "DatabaseName": "BookStore",
            "BooksCollectionName": "Books"
        },
        "Logging": {
            "LogLevel": {
                "Default": "Information",
                "Microsoft.AspNetCore": "Warning"
            }
        },
        "AllowedHosts": "*"
    }
    
  2. Adicione uma classe BookStoreDatabaseSettings ao diretório Modelos com o seguinte código:

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

    A classe anterior BookStoreDatabaseSettings é usada para armazenar os valores de propriedade BookStoreDatabase do arquivo appsettings.json. Os nomes de propriedade JSON e C# são nomeados de forma idêntica para facilitar o processo de mapeamento.

  3. Adicione o código realçado a seguir a Program.cs:

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

    No código anterior, a instância de configuração à qual a seção BookStoreDatabase do arquivo appsettings.json é registrada no contêiner de DI (Injeção de Dependência). Por exemplo, a propriedade ConnectionString de um objeto BookStoreDatabaseSettings é populada com a propriedade BookStoreDatabase:ConnectionString no appsettings.json.

  4. Adicione o seguinte código na parte superior do Program.cs para resolver a referência BookStoreDatabaseSettings:

    using BookStoreApi.Models;
    

Adicionar um serviço de operações CRUD

  1. Adicione um diretório Serviços à raiz do projeto.

  2. Adicione uma classe BooksService ao diretório Serviços com o seguinte código:

    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);
    }
    

    No código anterior, uma instância BookStoreDatabaseSettings é recuperada da DI por meio da injeção de construtor. Essa técnica fornece acesso para os valores de configuração do appsettings.json que foram adicionados na seção Adicionar um modelo de configuração.

  3. Adicione o código realçado a seguir a Program.cs:

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

    No código anterior, a classe BooksService é registrada com a DI para dar suporte à injeção de construtor nas classes consumidoras. O tempo de vida do serviço singleton é mais apropriado porque BooksService usa uma dependência direta de MongoClient. De acordo com as Diretrizes oficiais de reutilização do cliente Mongo, o MongoClient deve ser registrado na DI com um tempo de vida do serviço singleton.

  4. Adicione o seguinte código na parte superior do Program.cs para resolver a referência BooksService:

    using BookStoreApi.Services;
    

A classe BooksService usa os seguintes membros MongoDB.Driver para executar operações CRUD em relação ao banco de dados:

  • MongoClient: lê a instância do servidor para executar operações de banco de dados. O construtor dessa classe é fornecido na cadeia de conexão do 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: representa o banco de dados Mongo para execução de operações. Este tutorial usa o método GetCollection<TDocument>(coleção) genérico na interface para obter acesso aos dados em uma coleção específica. Execute operações CRUD em relação à coleção depois que esse método for chamado. Na chamada de método GetCollection<TDocument>(collection):

    • collection representa o nome da coleção.
    • TDocument representa o tipo de objeto CLR armazenado na coleção.

GetCollection<TDocument>(collection) retorna um objeto MongoCollection que representa a coleção. Neste tutorial, os seguintes métodos são invocados na coleção:

  • DeleteOneAsync: exclui um único documento que corresponde aos critérios de pesquisa fornecidos.
  • Encontrar<TDocument>: retorna todos os documentos na coleção que correspondem aos critérios de pesquisa fornecidos.
  • InsertOneAsync: insere o objeto fornecido como um novo documento na coleção.
  • ReplaceOneAsync: substitui o único documento que corresponde aos critérios de pesquisa fornecidos com o objeto fornecido.

Adicionar um controlador

Adicione uma classe BooksController ao diretório Controladores com o seguinte código:

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();
    }
}

O controlador da API Web anterior:

  • Usa a classe BooksService para executar operações CRUD.
  • Contém métodos de ação para dar suporte a solicitações GET, POST, PUT e DELETE HTTP.
  • Chama o CreatedAtAction no método de ação Create para retornar uma resposta HTTP 201. O código de status 201 é a resposta padrão para um método HTTP POST que cria um recurso no servidor. CreatedAtAction também adiciona um cabeçalho Location à resposta. O cabeçalho Location especifica o URI do livro recém-criado.

Testar a API Web

  1. Compile e execute o aplicativo.

  2. Navegue até https://localhost:<port>/api/books, onde <port> é o número da porta atribuído automaticamente para o aplicativo, para testar o método de ação Get sem parâmetros do controlador. Uma resposta JSON semelhante à apresentada a seguir será exibida:

    [
      {
        "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. Navegue até https://localhost:<port>/api/books/{id here} para testar o método de ação Get sobrecarregado do controlador. Uma resposta JSON semelhante à apresentada a seguir será exibida:

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

Configurar opções de serialização JSON

Há dois detalhes alterar sobre as respostas JSON retornadas na seção Testar a API Web:

  • O uso de maiúsculas e minúsculas padrão dos nomes da propriedade deve ser alterado para corresponder ao uso de maiúsculas e minúsculas Pascal dos nomes de propriedade do objeto CLR.
  • A propriedade bookName deve ser retornada como Name.

Para cumprir os requisitos anteriores, faça as seguintes alterações:

  1. Em Program.cs, encadeie o seguinte código realçado para a chamada de método 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);
    

    Com a alteração anterior, os nomes de propriedade na resposta JSON serializada da API Web correspondem aos respectivos nomes de propriedade no tipo de objeto CLR. Por exemplo, a propriedade Author da classe Book é serializada como Author ao invés de author.

  2. No Models/Book.cs, anote a propriedade BookName com o atributo [JsonPropertyName]:

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

    O valor do atributo [JsonPropertyName] de Name representa o nome da propriedade da resposta JSON serializada da API Web.

  3. Adicione o seguinte código na parte superior do Models/Book.cs para resolver a referência [JsonProperty] do atributo:

    using System.Text.Json.Serialization;
    
  4. Repita as etapas definidas na seção Testar a API Web. Observe a diferença nos nomes de propriedade JSON.

Adicionar suporte de autenticação a uma API Web

O ASP.NET Core Identity adiciona a funcionalidade de logon da interface do usuário aos aplicativos Web do ASP.NET Core. Para proteger APIs Web e SPAs, use uma das seguintes opções:

O Duende Identity Server é uma estrutura do OpenID Connect e OAuth 2.0 para ASP.NET Core. O Duende Identity Server habilita os seguintes recursos de segurança:

  • AaaS (autenticação como serviço)
  • SSO (logon único) em vários tipos de aplicativo
  • Controle de acesso para APIs
  • Federation Gateway

Importante

O Software Duende pode exigir que você pague uma taxa de licença pelo uso de produção do Duende Identity Server. Para obter mais informações, consulte Migrar do ASP.NET Core 5.0 para o 6.0.

Para obter mais informações, confira a documentação do Duende Identity Server (site da Duende Software).

Recursos adicionais

Este tutorial cria uma API Web que executa as operações CRUD (criar, ler, atualizar e excluir) em um banco de dados NoSQL do MongoDB.

Neste tutorial, você aprenderá como:

  • Configurar o MongoDB
  • Criar um banco de dados do MongoDB
  • Definir uma coleção e um esquema do MongoDB
  • Executar operações CRUD do MongoDB a partir de uma API Web
  • Personalizar a serialização JSON

Exibir ou baixar código de exemplo (como baixar)

Pré-requisitos

Configurar o MongoDB

Se você usar o Windows, o MongoDB será instalado em C:\Arquivos de Programas\MongoDB por padrão. Adicione C:\Arquivos de Programas\MongoDB\Server<número_de_versão>\bin à variável de ambiente Path. Essa alteração possibilita o acesso ao MongoDB a partir de qualquer lugar em seu computador de desenvolvimento.

Use o Shell do mongo nas etapas a seguir para criar um banco de dados, fazer coleções e armazenar documentos. Para saber mais sobre os comandos de Shell do mongo, consulte Como trabalhar com o Shell do mongo.

  1. Escolha um diretório no seu computador de desenvolvimento para armazenar os dados. Por exemplo, C:\BooksData no Windows. Crie o diretório se não houver um. O Shell do mongo não cria novos diretórios.

  2. Abra um shell de comando. Execute o comando a seguir para se conectar ao MongoDB na porta padrão 27017. Lembre-se de substituir <data_directory_path> pelo diretório escolhido na etapa anterior.

    mongod --dbpath <data_directory_path>
    
  3. Abra outra instância do shell de comando. Conecte-se ao banco de dados de testes padrão executando o seguinte comando:

    mongo
    
  4. Execute o seguinte comando em um shell de comando:

    use BookstoreDb
    

    Se ele ainda não existir, um banco de dados chamado BookstoreDb será criado. Se o banco de dados existir, a conexão dele será aberta para transações.

  5. Crie uma coleção Books usando o seguinte comando:

    db.createCollection('Books')
    

    O seguinte resultado é exibido:

    { "ok" : 1 }
    
  6. Defina um esquema para a coleção Books e insira dois documentos usando o seguinte comando:

    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'}])
    

    O seguinte resultado é exibido:

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

    Observação

    As IDs mostradas neste artigo não corresponderão às IDs de quando você executar esse exemplo.

  7. Visualize os documentos no banco de dados usando o seguinte comando:

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

    O seguinte resultado é exibido:

    {
      "_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"
    }
    

    O esquema adiciona uma propriedade _id gerada automaticamente do tipo ObjectId para cada documento.

O banco de dados está pronto. Você pode começar a criar a API Web do ASP.NET Core.

Criar o projeto da API Web do ASP.NET Core

  1. Acesse Arquivo>Novo>Projeto.

  2. Selecione o tipo de projeto aplicativo Web ASP.NET Core e, em seguida, Avançar.

  3. Nomeie o projeto como BooksApi e selecione criar.

  4. Selecione a estrutura de destino .NET Core e ASP.NET Core 3.0. Selecione o modelo de projeto API e, em seguida, Criar.

  5. Visite a Galeria do NuGet: MongoDB.Driver para determinar a versão estável mais recente do driver .NET para MongoDB. Na janela Console do Gerenciador de Pacotes, navegue até a raiz do projeto. Execute o seguinte comando para instalar o driver .NET para MongoDB:

    Install-Package MongoDB.Driver -Version {VERSION}
    

Adicionar um modelo de entidade

  1. Adicione um diretório Modelos à raiz do projeto.

  2. Adicione uma classe Book ao diretório Modelos com o seguinte código:

    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; }
        }
    }
    

    Na classe anterior, a propriedade Id é:

    • Necessária para mapear o objeto CLR (Common Language Runtime) para a coleção do MongoDB.
    • Anotada com [BsonId] para designar essa propriedade como a chave primária do documento.
    • Anotada com [BsonRepresentation(BsonType.ObjectId)] para permitir a passagem do parâmetro como tipo string, em vez de uma estrutura ObjectId. O Mongo processa a conversão de string para ObjectId.

    A propriedade BookName é anotada com o atributo [BsonElement]. O valor do atributo de Name representa o nome da propriedade da coleção do MongoDB.

Adicionar um modelo de configuração

  1. Adicione os seguintes valores de configuração de banco de dados a appsettings.json:

    {
      "BookstoreDatabaseSettings": {
        "BooksCollectionName": "Books",
        "ConnectionString": "mongodb://localhost:27017",
        "DatabaseName": "BookstoreDb"
      },
      "Logging": {
        "IncludeScopes": false,
        "Debug": {
          "LogLevel": {
            "Default": "Warning"
          }
        },
        "Console": {
          "LogLevel": {
            "Default": "Warning"
          }
        }
      }
    }
    
  2. Adicione uma classe BookstoreDatabaseSettings.cs ao diretório Modelos com o seguinte código:

    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; }
        }
    }
    

    A classe anterior BookstoreDatabaseSettings é usada para armazenar os valores de propriedade BookstoreDatabaseSettings do arquivo appsettings.json. Os nomes de propriedade JSON e C# são nomeados de forma idêntica para facilitar o processo de mapeamento.

  3. Adicione o código realçado a seguir a 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();
    }
    

    No código anterior:

    • A instância de configuração à qual a seção BookstoreDatabaseSettings do arquivo appsettings.json é associada é registrada no contêiner de DI (Injeção de Dependência). Por exemplo, a propriedade ConnectionString de um objeto BookstoreDatabaseSettings é populada com a propriedade BookstoreDatabaseSettings:ConnectionString no appsettings.json.
    • A interface IBookstoreDatabaseSettings é registrada na DI com um tempo de vida do serviço singleton. Quando inserida, a instância da interface é resolvida para um objeto BookstoreDatabaseSettings.
  4. Adicione o seguinte código na parte superior do Startup.cs para resolver as referências BookstoreDatabaseSettings e IBookstoreDatabaseSettings:

    using BooksApi.Models;
    

Adicionar um serviço de operações CRUD

  1. Adicione um diretório Serviços à raiz do projeto.

  2. Adicione uma classe BookService ao diretório Serviços com o seguinte código:

    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);
        }
    }
    

    No código anterior, uma instância IBookstoreDatabaseSettings é recuperada da DI por meio da injeção de construtor. Essa técnica fornece acesso para os valores de configuração do appsettings.json que foram adicionados na seção Adicionar um modelo de configuração.

  3. Adicione o código realçado a seguir a 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();
    }
    

    No código anterior, a classe BookService é registrada com a DI para dar suporte à injeção de construtor nas classes consumidoras. O tempo de vida do serviço singleton é mais apropriado porque BookService usa uma dependência direta de MongoClient. De acordo com as Diretrizes oficiais de reutilização do cliente Mongo, o MongoClient deve ser registrado na DI com um tempo de vida do serviço singleton.

  4. Adicione o seguinte código na parte superior do Startup.cs para resolver a referência BookService:

    using BooksApi.Services;
    

A classe BookService usa os seguintes membros MongoDB.Driver para executar operações CRUD em relação ao banco de dados:

  • MongoClient: lê a instância do servidor para executar operações de banco de dados. O construtor dessa classe é fornecido na cadeia de conexão do MongoDB:

    public BookService(IBookstoreDatabaseSettings settings)
    {
        var client = new MongoClient(settings.ConnectionString);
        var database = client.GetDatabase(settings.DatabaseName);
    
        _books = database.GetCollection<Book>(settings.BooksCollectionName);
    }
    
  • IMongoDatabase: representa o banco de dados Mongo para execução de operações. Este tutorial usa o método GetCollection<TDocument>(coleção) genérico na interface para obter acesso aos dados em uma coleção específica. Execute operações CRUD em relação à coleção depois que esse método for chamado. Na chamada de método GetCollection<TDocument>(collection):

    • collection representa o nome da coleção.
    • TDocument representa o tipo de objeto CLR armazenado na coleção.

GetCollection<TDocument>(collection) retorna um objeto MongoCollection que representa a coleção. Neste tutorial, os seguintes métodos são invocados na coleção:

  • DeleteOne: exclui um único documento que corresponde aos critérios de pesquisa fornecidos.
  • Find<TDocument>> retorna todos os documentos na coleção que correspondem aos critérios de pesquisa fornecidos.
  • InsertOne: insere o objeto fornecido como um novo documento na coleção.
  • ReplaceOne: substitui o único documento que corresponde aos critérios de pesquisa fornecidos com o objeto fornecido.

Adicionar um controlador

Adicione uma classe BooksController ao diretório Controladores com o seguinte código:

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();
        }
    }
}

O controlador da API Web anterior:

  • Usa a classe BookService para executar operações CRUD.
  • Contém métodos de ação para dar suporte a solicitações GET, POST, PUT e DELETE HTTP.
  • Chama o CreatedAtRoute no método de ação Create para retornar uma resposta HTTP 201. O código de status 201 é a resposta padrão para um método HTTP POST que cria um recurso no servidor. CreatedAtRoute também adiciona um cabeçalho Location à resposta. O cabeçalho Location especifica o URI do livro recém-criado.

Testar a API Web

  1. Compile e execute o aplicativo.

  2. Navegue até https://localhost:<port>/api/books para testar o método de ação Get sem parâmetros do controlador. A seguinte resposta JSON é exibida:

    [
      {
        "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. Navegue até https://localhost:<port>/api/books/{id here} para testar o método de ação Get sobrecarregado do controlador. A seguinte resposta JSON é exibida:

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

Configurar opções de serialização JSON

Há dois detalhes alterar sobre as respostas JSON retornadas na seção Testar a API Web:

  • O uso de maiúsculas e minúsculas padrão dos nomes da propriedade deve ser alterado para corresponder ao uso de maiúsculas e minúsculas Pascal dos nomes de propriedade do objeto CLR.
  • A propriedade bookName deve ser retornada como Name.

Para cumprir os requisitos anteriores, faça as seguintes alterações:

  1. O JSON.NET foi removido da estrutura compartilhada do ASP.NET. Adicione uma referência de pacote para Microsoft.AspNetCore.Mvc.NewtonsoftJson.

  2. Em Startup.ConfigureServices, encadeie o seguinte código realçado para a chamada de método 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());
    }
    

    Com a alteração anterior, os nomes de propriedade na resposta JSON serializada da API Web correspondem aos respectivos nomes de propriedade no tipo de objeto CLR. Por exemplo, a propriedade Author da classe Book é serializada como Author.

  3. No Models/Book.cs, anote a propriedade BookName com o atributo [JsonProperty] a seguir:

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

    O valor do atributo [JsonProperty] de Name representa o nome da propriedade da resposta JSON serializada da API Web.

  4. Adicione o seguinte código na parte superior do Models/Book.cs para resolver a referência [JsonProperty] do atributo:

    using Newtonsoft.Json;
    
  5. Repita as etapas definidas na seção Testar a API Web. Observe a diferença nos nomes de propriedade JSON.

Adicionar suporte de autenticação a uma API Web

O ASP.NET Core Identity adiciona a funcionalidade de logon da interface do usuário aos aplicativos Web do ASP.NET Core. Para proteger APIs Web e SPAs, use uma das seguintes opções:

O Duende Identity Server é uma estrutura do OpenID Connect e OAuth 2.0 para ASP.NET Core. O Duende Identity Server habilita os seguintes recursos de segurança:

  • AaaS (autenticação como serviço)
  • SSO (logon único) em vários tipos de aplicativo
  • Controle de acesso para APIs
  • Federation Gateway

Para obter mais informações, confira Visão Geral do Duende IdentityServer.

Para obter mais informações sobre outros provedores de autenticação, consulte Opções de autenticação de OSS da comunidade para ASP.NET Core

Próximas etapas

Para saber mais sobre a criação de APIs Web do ASP.NET Core, confira os seguintes recursos: