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 a versão atual, consulte a versão do .NET 9 deste artigo.

Aviso

Esta versão do ASP.NET Core não tem mais suporte. Para obter mais informações, consulte a Política de Suporte do .NET e do .NET Core. Para a versão atual, consulte a versão do .NET 9 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 a versão atual, consulte a versão do .NET 9 deste artigo.

Por Pratik Khandelwal e Scott Addie

Este tutorial cria uma API Web que executa 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: O Shell do MongoDB (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 no qual 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:\Arquivos de Programas\MongoDB por padrão. Adicione C:\Program Files\MongoDB\Server\<version_number>\bin à variável de PATH ambiente.
  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.exeou executando o seguinte comando no shell de comando:

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

    use BookStore
    

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

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

    db.createCollection('Books')
    

    O seguinte resultado é exibido:

    { "ok" : 1 }
    
  4. 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 terminal de comando.

  5. 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. Vá para Arquivo>Novo>Projeto.
  2. Selecione o tipo de projeto da API Web ASP.NET Core e selecione Avançar.
  3. Nomeie o projeto BookStoreApi e selecione Avançar.
  4. Na diálogo de Informações adicionais:
  • Confirme se o Framework é .NET 9.0 (Suporte Padrão).
  • Verifique se a caixa de seleção de Usar controladores está marcada.
  • Confirme se a caixa de seleção para habilitar o suporte ao OpenAPI está marcada.
  • Selecione Criar.
  1. 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 Models à raiz do projeto.

  2. Adicione uma Book classe ao diretório Models 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.
    • Anotado 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 BookStoreDatabaseSettings classe ao diretório Models 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 appsettings.json do arquivo BookStoreDatabase. 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 appsettings.json do arquivo BookStoreDatabase se associa é registrada no contêiner de Injeção de Dependência (DI). Por exemplo, a propriedade BookStoreDatabaseSettings de um objeto ConnectionString é 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 de Serviços à raiz do projeto.

  2. Adicione uma BooksService classe ao diretório de 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 aos appsettings.json valores de configuração 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, MongoClient deve ser registrado em DI com um tempo de vida de 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 operações em execução. Este tutorial usa o método genérico GetCollection<TDocument>(collection) 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 pelo objeto fornecido.

Adicionar um controlador

Adicione uma BooksController classe ao diretório Controllers 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 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.

Configurar opções de serialização JSON

Há dois detalhes a serem alterados 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 Book da classe Author é 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 em nomes de propriedade JSON.

Testar a API Web

Este tutorial usa o Gerenciador de Pontos de Extremidade e os arquivos .http para testar a API.

  1. Compile e execute o aplicativo.

  2. No Explorador de Endpoints, clique com o botão direito do mouse no endpoint GET/api/booksprimeiro e selecione Gerar solicitação.

    O conteúdo a seguir é adicionado ao BookStoreApi.http arquivo. Se essa for a primeira vez que uma solicitação é gerada, o arquivo é criado na raiz do projeto.

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

    O número da porta já deve ser definido como a porta usada pelo aplicativo, por exemplo, https://localhost:56874. Se esse não for o caso, você poderá encontrar o número da porta na janela de saída quando iniciar o aplicativo.

  3. Selecione o link Enviar solicitação acima da nova GET linha de solicitação.

    A solicitação GET é enviada ao aplicativo e a resposta é exibida no painel Resposta .

  4. O corpo da resposta apresenta o resultado JSON que contém as entradas do livro semelhantes a estas:

    [
      {
        "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. Para recuperar um único livro, clique com o botão direito do /api/books/{id}, params (string id) mouse no ponto de extremidade GET no Gerenciador de Pontos de Extremidade e selecione Gerar solicitação.

    O seguinte conteúdo é acrescentado ao BookStoreApi.http arquivo:

    @id=string
    GET {{BookStoreApi_HostAddress}}/api/books/{{id}}
    
    ###
    
  6. Substitua id a variável por uma das IDs retornadas da solicitação anterior, por exemplo:

    @id="61a6058e6c43f32854e51f52"
    GET {{BookStoreApi_HostAddress}}/api/books/{{id}}
    
    ###
    
  7. Selecione o link Enviar solicitação acima da nova GET linha de solicitação.

    A solicitação GET é enviada ao aplicativo e a resposta é exibida no painel Resposta .

  8. O corpo da resposta apresenta um JSON semelhante ao seguinte:

    {
      "Id": "61a6058e6c43f32854e51f52",
      "Name": "Clean Code",
      "Price": 43.15,
      "Category": "Computers",
      "Author": "Robert C. Martin"
    }
    
  9. Para testar o ponto de extremidade POST, clique com o botão direito do mouse no /api/books ponto de extremidade POST e selecione Gerar solicitação.

    O seguinte conteúdo é adicionado ao arquivo BookStoreApi.http:

    POST {{BookStoreApi_HostAddress}}/api/books
    Content-Type: application/json
    
    {
      //Book
    }
    
    ###
    
  10. Substitua o comentário do Livro por um objeto de livro, como o corpo da solicitação JSON:

    POST {{BookStoreApi_HostAddress}}/api/books
    Content-Type: application/json
    
     {
       "Name": "The Pragmatic Programmer",
       "Price": 49.99,
       "Category": "Computers",
       "Author": "Andy Hunt"
     }
    
    ###
    
  11. Selecione o link Enviar solicitação acima da linha de solicitação POST .

    A solicitação POST é enviada ao aplicativo e a resposta é exibida no painel Resposta . A resposta deve incluir o livro recém-criado com sua ID atribuída.

  12. Por fim, para excluir um livro, clique com o botão direito no endpoint /api/books/{id}, params (string id) e selecione Gerar solicitação.

    O seguinte conteúdo é acrescentado ao BookStoreApi.http arquivo:

    DELETE {{BookStoreApi_HostAddress}}/api/Books/{{id}}
    
    ###
    
  13. Substitua a id variável por uma das IDs retornadas da solicitação anterior e clique em Enviar solicitação. Por exemplo:

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

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
  • Portal de Federação

Importante

O Duende Software 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 no .NET 5 para o .NET 6.

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

Recursos adicionais

Este tutorial cria uma API Web que executa 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: O Shell do MongoDB (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 no qual 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:\Arquivos de Programas\MongoDB por padrão. Adicione C:\Program Files\MongoDB\Server\<version_number>\bin à variável de PATH ambiente.
  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.exeou executando o seguinte comando no shell de comando:

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

    use BookStore
    

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

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

    db.createCollection('Books')
    

    O seguinte resultado é exibido:

    { "ok" : 1 }
    
  4. 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 terminal de comando.

  5. 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. Vá para Arquivo>Novo>Projeto.

  2. Selecione o tipo de projeto da API Web ASP.NET Core e selecione Avançar.

  3. Nomeie o projeto BookStoreApi e selecione Avançar.

  4. Selecione a estrutura .NET 8.0 (suporte a 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 Models à raiz do projeto.

  2. Adicione uma Book classe ao diretório Models 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.
    • Anotado 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 BookStoreDatabaseSettings classe ao diretório Models 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 appsettings.json do arquivo BookStoreDatabase. 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 appsettings.json do arquivo BookStoreDatabase se associa é registrada no contêiner de Injeção de Dependência (DI). Por exemplo, a propriedade BookStoreDatabaseSettings de um objeto ConnectionString é 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 de Serviços à raiz do projeto.

  2. Adicione uma BooksService classe ao diretório de 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 aos appsettings.json valores de configuração 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, MongoClient deve ser registrado em DI com um tempo de vida de 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 operações em execução. Este tutorial usa o método genérico GetCollection<TDocument>(collection) 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 pelo objeto fornecido.

Adicionar um controlador

Adicione uma BooksController classe ao diretório Controllers 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 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 a serem alterados 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 Book da classe Author é 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 em 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
  • Portal de Federação

Importante

O Duende Software 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 no .NET 5 para o .NET 6.

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

Recursos adicionais

Este tutorial cria uma API Web que executa 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. No Windows, o MongoDB é instalado em C:\Arquivos de Programas\MongoDB por padrão. Adicione C:\Program Files\MongoDB\Server\<version_number>\bin à variável de PATH ambiente.

  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.exeou executando o seguinte comando no shell de comando:

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

    use BookStore
    

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

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

    db.createCollection('Books')
    

    O seguinte resultado é exibido:

    { "ok" : 1 }
    
  4. 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 terminal de comando.

  5. 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. Vá para Arquivo>Novo>Projeto.

  2. Selecione o tipo de projeto da API Web ASP.NET Core e selecione Avançar.

  3. Nomeie o projeto BookStoreApi e selecione Avançar.

  4. Selecione a estrutura .NET 7.0 (Suporte a Termos Padrão) 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 Models à raiz do projeto.

  2. Adicione uma Book classe ao diretório Models 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.
    • Anotado 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 BookStoreDatabaseSettings classe ao diretório Models 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 appsettings.json do arquivo BookStoreDatabase. 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 appsettings.json do arquivo BookStoreDatabase se associa é registrada no contêiner de Injeção de Dependência (DI). Por exemplo, a propriedade BookStoreDatabaseSettings de um objeto ConnectionString é 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 de Serviços à raiz do projeto.

  2. Adicione uma BooksService classe ao diretório de 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 aos appsettings.json valores de configuração 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, MongoClient deve ser registrado em DI com um tempo de vida de 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 desta classe recebe a string 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 operações em execução. Este tutorial usa o método genérico GetCollection<TDocument>(collection) 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 pelo objeto fornecido.

Adicionar um controlador

Adicione uma BooksController classe ao diretório Controllers 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 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 a serem alterados 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 Book da classe Author é 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 em 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
  • Portal de Federação

Importante

O Duende Software 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 no .NET 5 para o .NET 6.

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

Recursos adicionais

Este tutorial cria uma API Web que executa 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. No Windows, o MongoDB é instalado em C:\Arquivos de Programas\MongoDB por padrão. Adicione C:\Program Files\MongoDB\Server\<version_number>\bin à variável de PATH ambiente.

  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.exeou executando o seguinte comando no shell de comando:

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

    use BookStore
    

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

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

    db.createCollection('Books')
    

    O seguinte resultado é exibido:

    { "ok" : 1 }
    
  4. 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 terminal de comando.

  5. 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. Vá para Arquivo>Novo>Projeto.

  2. Selecione o tipo de projeto da API Web ASP.NET Core e selecione Avançar.

  3. Nomeie o projeto BookStoreApi e selecione Avançar.

  4. Selecione a estrutura .NET 6.0 (suporte a 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 Models à raiz do projeto.

  2. Adicione uma Book classe ao diretório Models 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.
    • Anotado 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 BookStoreDatabaseSettings classe ao diretório Models 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 appsettings.json do arquivo BookStoreDatabase. 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 appsettings.json do arquivo BookStoreDatabase se associa é registrada no contêiner de Injeção de Dependência (DI). Por exemplo, a propriedade BookStoreDatabaseSettings de um objeto ConnectionString é 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 de Serviços à raiz do projeto.

  2. Adicione uma BooksService classe ao diretório de 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 aos appsettings.json valores de configuração 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, MongoClient deve ser registrado em DI com um tempo de vida de 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 desta classe recebe a string 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 operações em execução. Este tutorial usa o método genérico GetCollection<TDocument>(collection) 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 pelo objeto fornecido.

Adicionar um controlador

Adicione uma BooksController classe ao diretório Controllers 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 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 a serem alterados 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 Book da classe Author é 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 em 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
  • Portal de Federação

Importante

O Duende Software 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 no .NET 5 para o .NET 6.

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

Recursos adicionais

Este tutorial cria uma API Web que executa 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 o código de exemplo (como baixar)

Pré-requisitos

Configurar o MongoDB

Se estiver usando o Windows, o MongoDB será instalado em C:\Arquivos de Programas\MongoDB por padrão. Adicione C:\Program Files\MongoDB\Server\<version_number>\bin à variável de Path ambiente. 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 obter mais informações sobre comandos do Mongo Shell, consulte Trabalhando 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
    

    Um banco de dados chamado BookstoreDb será criado se ele ainda não existir. 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. Vá para Arquivo>Novo>Projeto.

  2. Selecione o tipo de projeto ASP.NET Aplicativo Web Principal e selecione Avançar.

  3. Nomeie o projeto BooksApi e selecione Criar.

  4. Selecione a estrutura de destino do .NET Core e o ASP.NET Core 3.0. Selecione o modelo de projeto de API e selecione 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 Models à raiz do projeto.

  2. Adicione uma Book classe ao diretório Models 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.
    • Anotado 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 um BookstoreDatabaseSettings.cs arquivo 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 appsettings.json do arquivo BookstoreDatabaseSettings. 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 appsettings.json do arquivo BookstoreDatabaseSettings é associada é registrada no contêiner de DI (Injeção de Dependência). Por exemplo, a propriedade BookstoreDatabaseSettings de um objeto ConnectionString é populada com a propriedade BookstoreDatabaseSettings:ConnectionString no appsettings.json.
    • A IBookstoreDatabaseSettings interface é registrada em DI com um tempo de vida de 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 de Serviços à raiz do projeto.

  2. Adicione uma BookService classe ao diretório de 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 aos appsettings.json valores de configuração 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, MongoClient deve ser registrado em DI com um tempo de vida de 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 desta classe recebe a string 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 operações em execução. Este tutorial usa o método genérico GetCollection<TDocument>(collection) 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.
  • Encontrar<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 pelo objeto fornecido.

Adicionar um controlador

Adicione uma BooksController classe ao diretório Controllers 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 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 a serem alterados 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 Book da classe Author é 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 em 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 IdentityServer é uma estrutura do OpenID Connect e OAuth 2.0 para ASP.NET Core. O IdentityServer da Duende 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
  • Portal de Federação

Para obter mais informações, consulte Visão geral do Duende IdentityServer.

Para obter mais informações sobre outros provedores de autenticação, consulte as opções de autenticação do 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: