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 .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 .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 .NET 9 deste artigo.
Por Pratik Khandelwal e Scott Addie
Este tutorial cria uma API Web que executa as operações CRUD (criar, ler, atualizar e excluir) em um banco de dados NoSQL do MongoDB.
Neste tutorial, você aprenderá como:
- Configurar o MongoDB
- Criar um banco de dados do MongoDB
- Definir uma coleção e um esquema do MongoDB
- Executar operações CRUD do MongoDB a partir de uma API Web
- Personalizar a serialização JSON
Pré-requisitos
Visual Studio 2022 com a carga de trabalho de desenvolvimento Web e do ASP.NET.
Configurar o MongoDB
Habilite o acesso ao MongoDB e ao MongoDB Shell de qualquer lugar na máquina de desenvolvimento (Windows/Linux/macOS):
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 ambientePATH
. - Windows: MongoDB Shell (mongosh.exe) está instalado em C\Users<user>\AppData\Local\Programs\mongosh. Adicione o caminho resultante para
mongosh.exe
à variável de ambientePATH
.
- macOS/Linux: Escolha um diretório para extrair o Shell do MongoDB. Adicione o caminho resultante para
Baixe e instale o MongoDB:
- macOS/Linux: Verifique o diretório em que o MongoDB foi instalado, geralmente em /usr/local/mongodb. Adicione o caminho resultante para
mongodb
à variável de ambientePATH
. - Windows: O MongoDB é instalado em C:\Program Files\MongoDB por padrão. Adicione C:\Arquivos de Programas\MongoDB\Server<número_de_versão>\bin à variável de ambiente
PATH
.
- macOS/Linux: Verifique o diretório em que o MongoDB foi instalado, geralmente em /usr/local/mongodb. Adicione o caminho resultante para
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
.
- macOS/Linux: Por exemplo,
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
.
Abra uma instância do shell de comando do MongoDB iniciando
mongosh.exe
.No shell de comando, conecte-se ao banco de dados de teste padrão executando o seguinte comando:
mongosh
Execute o seguinte comando no shell de comando:
use BookStore
Um banco de dados chamado BookstoreDb será criado se ele já não existir. Se o banco de dados existir, a conexão dele será aberta para transações.
Crie uma coleção
Books
usando o seguinte comando:db.createCollection('Books')
O seguinte resultado é exibido:
{ "ok" : 1 }
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
ObjectId
s mostrados no resultado anterior não corresponderão aos mostrados no shell de comando.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 tipoObjectId
para cada documento.
Criar o projeto da API Web do ASP.NET Core
Acesse Arquivo>Novo>Projeto.
Selecione o tipo do projeto da API Web do ASP.NET Core e, em seguida, Avançar.
Nomeie o projeto como BookStoreApi e clique em Avançar.
Selecione a estrutura .NET 8.0 (suporte de longo prazo) e escolha Criar.
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
Adicione um diretório Modelos à raiz do projeto.
Adicione uma classe
Book
ao diretório Modelos com o seguinte código:using MongoDB.Bson; using MongoDB.Bson.Serialization.Attributes; namespace BookStoreApi.Models; public class Book { [BsonId] [BsonRepresentation(BsonType.ObjectId)] public string? Id { get; set; } [BsonElement("Name")] public string BookName { get; set; } = null!; public decimal Price { get; set; } public string Category { get; set; } = null!; public string Author { get; set; } = null!; }
Na classe anterior, a propriedade
Id
é:- Necessária para mapear o objeto CLR (Common Language Runtime) para a coleção do MongoDB.
- Anotada com
[BsonId]
para designar essa propriedade como a chave primária do documento. - Anotada com
[BsonRepresentation(BsonType.ObjectId)]
para permitir a passagem do parâmetro como tipostring
, em vez de uma estrutura ObjectId. O Mongo processa a conversão destring
paraObjectId
.
A propriedade
BookName
é anotada com o atributo[BsonElement]
. O valor do atributo deName
representa o nome da propriedade da coleção do MongoDB.
Adicionar um modelo de configuração
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": "*" }
Adicione uma classe
BookStoreDatabaseSettings
ao diretório Modelos com o seguinte código:namespace BookStoreApi.Models; public class BookStoreDatabaseSettings { public string ConnectionString { get; set; } = null!; public string DatabaseName { get; set; } = null!; public string BooksCollectionName { get; set; } = null!; }
A classe anterior
BookStoreDatabaseSettings
é usada para armazenar os valores de propriedadeBookStoreDatabase
do arquivoappsettings.json
. Os nomes de propriedade JSON e C# são nomeados de forma idêntica para facilitar o processo de mapeamento.Adicione o código realçado a seguir a
Program.cs
:var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.Configure<BookStoreDatabaseSettings>( builder.Configuration.GetSection("BookStoreDatabase"));
No código anterior, a instância de configuração à qual a seção
BookStoreDatabase
do arquivoappsettings.json
é registrada no contêiner de DI (Injeção de Dependência). Por exemplo, a propriedadeConnectionString
de um objetoBookStoreDatabaseSettings
é populada com a propriedadeBookStoreDatabase:ConnectionString
noappsettings.json
.Adicione o seguinte código na parte superior do
Program.cs
para resolver a referênciaBookStoreDatabaseSettings
:using BookStoreApi.Models;
Adicionar um serviço de operações CRUD
Adicione um diretório Serviços à raiz do projeto.
Adicione uma classe
BooksService
ao diretório Serviços com o seguinte código:using BookStoreApi.Models; using Microsoft.Extensions.Options; using MongoDB.Driver; namespace BookStoreApi.Services; public class BooksService { private readonly IMongoCollection<Book> _booksCollection; public BooksService( IOptions<BookStoreDatabaseSettings> bookStoreDatabaseSettings) { var mongoClient = new MongoClient( bookStoreDatabaseSettings.Value.ConnectionString); var mongoDatabase = mongoClient.GetDatabase( bookStoreDatabaseSettings.Value.DatabaseName); _booksCollection = mongoDatabase.GetCollection<Book>( bookStoreDatabaseSettings.Value.BooksCollectionName); } public async Task<List<Book>> GetAsync() => await _booksCollection.Find(_ => true).ToListAsync(); public async Task<Book?> GetAsync(string id) => await _booksCollection.Find(x => x.Id == id).FirstOrDefaultAsync(); public async Task CreateAsync(Book newBook) => await _booksCollection.InsertOneAsync(newBook); public async Task UpdateAsync(string id, Book updatedBook) => await _booksCollection.ReplaceOneAsync(x => x.Id == id, updatedBook); public async Task RemoveAsync(string id) => await _booksCollection.DeleteOneAsync(x => x.Id == id); }
No código anterior, uma instância
BookStoreDatabaseSettings
é recuperada da DI por meio da injeção de construtor. Essa técnica fornece acesso para os valores de configuração doappsettings.json
que foram adicionados na seção Adicionar um modelo de configuração.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 porqueBooksService
usa uma dependência direta deMongoClient
. De acordo com as Diretrizes oficiais de reutilização do cliente Mongo, oMongoClient
deve ser registrado na DI com um tempo de vida do serviço singleton.Adicione o seguinte código na parte superior do
Program.cs
para resolver a referênciaBooksService
:using BookStoreApi.Services;
A classe BooksService
usa os seguintes membros MongoDB.Driver
para executar operações CRUD em relação ao banco de dados:
MongoClient: lê a instância do servidor para executar operações de banco de dados. O construtor dessa classe é fornecido na cadeia de conexão do MongoDB:
public BooksService( IOptions<BookStoreDatabaseSettings> bookStoreDatabaseSettings) { var mongoClient = new MongoClient( bookStoreDatabaseSettings.Value.ConnectionString); var mongoDatabase = mongoClient.GetDatabase( bookStoreDatabaseSettings.Value.DatabaseName); _booksCollection = mongoDatabase.GetCollection<Book>( bookStoreDatabaseSettings.Value.BooksCollectionName); }
IMongoDatabase: representa o banco de dados Mongo para execução de operações. Este tutorial usa o método GetCollection<TDocument>(coleção) genérico na interface para obter acesso aos dados em uma coleção específica. Execute operações CRUD em relação à coleção depois que esse método for chamado. Na chamada de método
GetCollection<TDocument>(collection)
:collection
representa o nome da coleção.TDocument
representa o tipo de objeto CLR armazenado na coleção.
GetCollection<TDocument>(collection)
retorna um objeto MongoCollection que representa a coleção. Neste tutorial, os seguintes métodos são invocados na coleção:
- DeleteOneAsync: exclui um único documento que corresponde aos critérios de pesquisa fornecidos.
- Encontrar<TDocument>: retorna todos os documentos na coleção que correspondem aos critérios de pesquisa fornecidos.
- InsertOneAsync: insere o objeto fornecido como um novo documento na coleção.
- ReplaceOneAsync: substitui o único documento que corresponde aos critérios de pesquisa fornecidos com o objeto fornecido.
Adicionar um controlador
Adicione uma classe BooksController
ao diretório Controladores com o seguinte código:
using BookStoreApi.Models;
using BookStoreApi.Services;
using Microsoft.AspNetCore.Mvc;
namespace BookStoreApi.Controllers;
[ApiController]
[Route("api/[controller]")]
public class BooksController : ControllerBase
{
private readonly BooksService _booksService;
public BooksController(BooksService booksService) =>
_booksService = booksService;
[HttpGet]
public async Task<List<Book>> Get() =>
await _booksService.GetAsync();
[HttpGet("{id:length(24)}")]
public async Task<ActionResult<Book>> Get(string id)
{
var book = await _booksService.GetAsync(id);
if (book is null)
{
return NotFound();
}
return book;
}
[HttpPost]
public async Task<IActionResult> Post(Book newBook)
{
await _booksService.CreateAsync(newBook);
return CreatedAtAction(nameof(Get), new { id = newBook.Id }, newBook);
}
[HttpPut("{id:length(24)}")]
public async Task<IActionResult> Update(string id, Book updatedBook)
{
var book = await _booksService.GetAsync(id);
if (book is null)
{
return NotFound();
}
updatedBook.Id = book.Id;
await _booksService.UpdateAsync(id, updatedBook);
return NoContent();
}
[HttpDelete("{id:length(24)}")]
public async Task<IActionResult> Delete(string id)
{
var book = await _booksService.GetAsync(id);
if (book is null)
{
return NotFound();
}
await _booksService.RemoveAsync(id);
return NoContent();
}
}
O controlador da API Web anterior:
- Usa a classe
BooksService
para executar operações CRUD. - Contém métodos de ação para dar suporte a solicitações GET, POST, PUT e DELETE HTTP.
- Chama o CreatedAtAction no método de ação
Create
para retornar uma resposta HTTP 201. O código de status 201 é a resposta padrão para um método HTTP POST que cria um recurso no servidor.CreatedAtAction
também adiciona um cabeçalhoLocation
à resposta. O cabeçalhoLocation
especifica o URI do livro recém-criado.
Testar a API Web
Compile e execute o aplicativo.
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çãoGet
sem parâmetros do controlador, selecione Experimente>Executar. Uma resposta JSON semelhante à apresentada a seguir será exibida:[ { "id": "61a6058e6c43f32854e51f51", "bookName": "Design Patterns", "price": 54.93, "category": "Computers", "author": "Ralph Johnson" }, { "id": "61a6058e6c43f32854e51f52", "bookName": "Clean Code", "price": 43.15, "category": "Computers", "author": "Robert C. Martin" } ]
Navegue até
https://localhost:<port>/api/books/{id here}
para testar o método de açãoGet
sobrecarregado do controlador. Uma resposta JSON semelhante à apresentada a seguir será exibida:{ "id": "61a6058e6c43f32854e51f52", "bookName": "Clean Code", "price": 43.15, "category": "Computers", "author": "Robert C. Martin" }
Configurar opções de serialização JSON
Há dois detalhes alterar sobre as respostas JSON retornadas na seção Testar a API Web:
- O uso de maiúsculas e minúsculas padrão dos nomes da propriedade deve ser alterado para corresponder ao uso de maiúsculas e minúsculas Pascal dos nomes de propriedade do objeto CLR.
- A propriedade
bookName
deve ser retornada comoName
.
Para cumprir os requisitos anteriores, faça as seguintes alterações:
Em
Program.cs
, encadeie o seguinte código realçado para a chamada de métodoAddControllers
:var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.Configure<BookStoreDatabaseSettings>( builder.Configuration.GetSection("BookStoreDatabase")); builder.Services.AddSingleton<BooksService>(); builder.Services.AddControllers() .AddJsonOptions( options => options.JsonSerializerOptions.PropertyNamingPolicy = null);
Com a alteração anterior, os nomes de propriedade na resposta JSON serializada da API Web correspondem aos respectivos nomes de propriedade no tipo de objeto CLR. Por exemplo, a propriedade
Author
da classeBook
é serializada comoAuthor
ao invés deauthor
.No
Models/Book.cs
, anote a propriedadeBookName
com o atributo[JsonPropertyName]
:[BsonElement("Name")] [JsonPropertyName("Name")] public string BookName { get; set; } = null!;
O valor do atributo
[JsonPropertyName]
deName
representa o nome da propriedade da resposta JSON serializada da API Web.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;
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:
- Microsoft Entra ID
- Azure Active Directory B2C (Azure AD B2C)
- Duende Identity Server
O Duende Identity Server é uma estrutura do OpenID Connect e OAuth 2.0 para ASP.NET Core. O Duende Identity Server habilita os seguintes recursos de segurança:
- AaaS (autenticação como serviço)
- SSO (logon único) em vários tipos de aplicativo
- Controle de acesso para APIs
- Federation Gateway
Importante
O Software Duende pode exigir que você pague uma taxa de licença pelo uso de produção do Duende Identity Server. Para obter mais informações, consulte Migrar do ASP.NET Core 5.0 para o 6.0.
Para obter mais informações, confira a documentação do Duende Identity Server (site da Duende Software).
Recursos adicionais
Este tutorial cria uma API Web que executa as operações CRUD (criar, ler, atualizar e excluir) em um banco de dados NoSQL do MongoDB.
Neste tutorial, você aprenderá como:
- Configurar o MongoDB
- Criar um banco de dados do MongoDB
- Definir uma coleção e um esquema do MongoDB
- Executar operações CRUD do MongoDB a partir de uma API Web
- Personalizar a serialização JSON
Pré-requisitos
Visual Studio 2022 com a carga de trabalho de desenvolvimento Web e do ASP.NET.
Configurar o MongoDB
Habilite o acesso ao Shell do MongoDB e do Mongo DB de qualquer lugar no computador de desenvolvimento:
Se você usar o Windows, o MongoDB será instalado em C:\Arquivos de Programas\MongoDB por padrão. Adicione C:\Arquivos de Programas\MongoDB\Server<número_de_versão>>\bin à variável de ambiente
PATH
.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 ambientePATH
.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.
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
.
Abra uma instância do shell de comando do MongoDB iniciando
mongosh.exe
.Conecte-se ao banco de dados de testes padrão executando o seguinte comando no shell de comando:
mongosh
Execute o seguinte comando no shell de comando:
use BookStore
Um banco de dados chamado BookstoreDb será criado se ele já não existir. Se o banco de dados existir, a conexão dele será aberta para transações.
Crie uma coleção
Books
usando o seguinte comando:db.createCollection('Books')
O seguinte resultado é exibido:
{ "ok" : 1 }
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
ObjectId
s mostrados no resultado anterior não corresponderão aos mostrados no shell de comando.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 tipoObjectId
para cada documento.
Criar o projeto da API Web do ASP.NET Core
Acesse Arquivo>Novo>Projeto.
Selecione o tipo do projeto da API Web do ASP.NET Core e, em seguida, Avançar.
Nomeie o projeto como BookStoreApi e clique em Avançar.
Selecione a estrutura .NET 7.0 (Standard Term Support) e selecione Criar.
No menu Ferramentas selecione Gerenciador de Pacotes NuGet>Console do Gerenciador de Pacotes.
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
Adicione um diretório Modelos à raiz do projeto.
Adicione uma classe
Book
ao diretório Modelos com o seguinte código:using MongoDB.Bson; using MongoDB.Bson.Serialization.Attributes; namespace BookStoreApi.Models; public class Book { [BsonId] [BsonRepresentation(BsonType.ObjectId)] public string? Id { get; set; } [BsonElement("Name")] public string BookName { get; set; } = null!; public decimal Price { get; set; } public string Category { get; set; } = null!; public string Author { get; set; } = null!; }
Na classe anterior, a propriedade
Id
é:- Necessária para mapear o objeto CLR (Common Language Runtime) para a coleção do MongoDB.
- Anotada com
[BsonId]
para designar essa propriedade como a chave primária do documento. - Anotada com
[BsonRepresentation(BsonType.ObjectId)]
para permitir a passagem do parâmetro como tipostring
, em vez de uma estrutura ObjectId. O Mongo processa a conversão destring
paraObjectId
.
A propriedade
BookName
é anotada com o atributo[BsonElement]
. O valor do atributo deName
representa o nome da propriedade da coleção do MongoDB.
Adicionar um modelo de configuração
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": "*" }
Adicione uma classe
BookStoreDatabaseSettings
ao diretório Modelos com o seguinte código:namespace BookStoreApi.Models; public class BookStoreDatabaseSettings { public string ConnectionString { get; set; } = null!; public string DatabaseName { get; set; } = null!; public string BooksCollectionName { get; set; } = null!; }
A classe anterior
BookStoreDatabaseSettings
é usada para armazenar os valores de propriedadeBookStoreDatabase
do arquivoappsettings.json
. Os nomes de propriedade JSON e C# são nomeados de forma idêntica para facilitar o processo de mapeamento.Adicione o código realçado a seguir a
Program.cs
:var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.Configure<BookStoreDatabaseSettings>( builder.Configuration.GetSection("BookStoreDatabase"));
No código anterior, a instância de configuração à qual a seção
BookStoreDatabase
do arquivoappsettings.json
é registrada no contêiner de DI (Injeção de Dependência). Por exemplo, a propriedadeConnectionString
de um objetoBookStoreDatabaseSettings
é populada com a propriedadeBookStoreDatabase:ConnectionString
noappsettings.json
.Adicione o seguinte código na parte superior do
Program.cs
para resolver a referênciaBookStoreDatabaseSettings
:using BookStoreApi.Models;
Adicionar um serviço de operações CRUD
Adicione um diretório Serviços à raiz do projeto.
Adicione uma classe
BooksService
ao diretório Serviços com o seguinte código:using BookStoreApi.Models; using Microsoft.Extensions.Options; using MongoDB.Driver; namespace BookStoreApi.Services; public class BooksService { private readonly IMongoCollection<Book> _booksCollection; public BooksService( IOptions<BookStoreDatabaseSettings> bookStoreDatabaseSettings) { var mongoClient = new MongoClient( bookStoreDatabaseSettings.Value.ConnectionString); var mongoDatabase = mongoClient.GetDatabase( bookStoreDatabaseSettings.Value.DatabaseName); _booksCollection = mongoDatabase.GetCollection<Book>( bookStoreDatabaseSettings.Value.BooksCollectionName); } public async Task<List<Book>> GetAsync() => await _booksCollection.Find(_ => true).ToListAsync(); public async Task<Book?> GetAsync(string id) => await _booksCollection.Find(x => x.Id == id).FirstOrDefaultAsync(); public async Task CreateAsync(Book newBook) => await _booksCollection.InsertOneAsync(newBook); public async Task UpdateAsync(string id, Book updatedBook) => await _booksCollection.ReplaceOneAsync(x => x.Id == id, updatedBook); public async Task RemoveAsync(string id) => await _booksCollection.DeleteOneAsync(x => x.Id == id); }
No código anterior, uma instância
BookStoreDatabaseSettings
é recuperada da DI por meio da injeção de construtor. Essa técnica fornece acesso para os valores de configuração doappsettings.json
que foram adicionados na seção Adicionar um modelo de configuração.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 porqueBooksService
usa uma dependência direta deMongoClient
. De acordo com as Diretrizes oficiais de reutilização do cliente Mongo, oMongoClient
deve ser registrado na DI com um tempo de vida do serviço singleton.Adicione o seguinte código na parte superior do
Program.cs
para resolver a referênciaBooksService
:using BookStoreApi.Services;
A classe BooksService
usa os seguintes membros MongoDB.Driver
para executar operações CRUD em relação ao banco de dados:
MongoClient: lê a instância do servidor para executar operações de banco de dados. O construtor dessa classe é fornecido na cadeia de conexão do MongoDB:
public BooksService( IOptions<BookStoreDatabaseSettings> bookStoreDatabaseSettings) { var mongoClient = new MongoClient( bookStoreDatabaseSettings.Value.ConnectionString); var mongoDatabase = mongoClient.GetDatabase( bookStoreDatabaseSettings.Value.DatabaseName); _booksCollection = mongoDatabase.GetCollection<Book>( bookStoreDatabaseSettings.Value.BooksCollectionName); }
IMongoDatabase: representa o banco de dados Mongo para execução de operações. Este tutorial usa o método GetCollection<TDocument>(coleção) genérico na interface para obter acesso aos dados em uma coleção específica. Execute operações CRUD em relação à coleção depois que esse método for chamado. Na chamada de método
GetCollection<TDocument>(collection)
:collection
representa o nome da coleção.TDocument
representa o tipo de objeto CLR armazenado na coleção.
GetCollection<TDocument>(collection)
retorna um objeto MongoCollection que representa a coleção. Neste tutorial, os seguintes métodos são invocados na coleção:
- DeleteOneAsync: exclui um único documento que corresponde aos critérios de pesquisa fornecidos.
- Encontrar<TDocument>: retorna todos os documentos na coleção que correspondem aos critérios de pesquisa fornecidos.
- InsertOneAsync: insere o objeto fornecido como um novo documento na coleção.
- ReplaceOneAsync: substitui o único documento que corresponde aos critérios de pesquisa fornecidos com o objeto fornecido.
Adicionar um controlador
Adicione uma classe BooksController
ao diretório Controladores com o seguinte código:
using BookStoreApi.Models;
using BookStoreApi.Services;
using Microsoft.AspNetCore.Mvc;
namespace BookStoreApi.Controllers;
[ApiController]
[Route("api/[controller]")]
public class BooksController : ControllerBase
{
private readonly BooksService _booksService;
public BooksController(BooksService booksService) =>
_booksService = booksService;
[HttpGet]
public async Task<List<Book>> Get() =>
await _booksService.GetAsync();
[HttpGet("{id:length(24)}")]
public async Task<ActionResult<Book>> Get(string id)
{
var book = await _booksService.GetAsync(id);
if (book is null)
{
return NotFound();
}
return book;
}
[HttpPost]
public async Task<IActionResult> Post(Book newBook)
{
await _booksService.CreateAsync(newBook);
return CreatedAtAction(nameof(Get), new { id = newBook.Id }, newBook);
}
[HttpPut("{id:length(24)}")]
public async Task<IActionResult> Update(string id, Book updatedBook)
{
var book = await _booksService.GetAsync(id);
if (book is null)
{
return NotFound();
}
updatedBook.Id = book.Id;
await _booksService.UpdateAsync(id, updatedBook);
return NoContent();
}
[HttpDelete("{id:length(24)}")]
public async Task<IActionResult> Delete(string id)
{
var book = await _booksService.GetAsync(id);
if (book is null)
{
return NotFound();
}
await _booksService.RemoveAsync(id);
return NoContent();
}
}
O controlador da API Web anterior:
- Usa a classe
BooksService
para executar operações CRUD. - Contém métodos de ação para dar suporte a solicitações GET, POST, PUT e DELETE HTTP.
- Chama o CreatedAtAction no método de ação
Create
para retornar uma resposta HTTP 201. O código de status 201 é a resposta padrão para um método HTTP POST que cria um recurso no servidor.CreatedAtAction
também adiciona um cabeçalhoLocation
à resposta. O cabeçalhoLocation
especifica o URI do livro recém-criado.
Testar a API Web
Compile e execute o aplicativo.
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çãoGet
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" } ]
Navegue até
https://localhost:<port>/api/books/{id here}
para testar o método de açãoGet
sobrecarregado do controlador. Uma resposta JSON semelhante à apresentada a seguir será exibida:{ "id": "61a6058e6c43f32854e51f52", "bookName": "Clean Code", "price": 43.15, "category": "Computers", "author": "Robert C. Martin" }
Configurar opções de serialização JSON
Há dois detalhes alterar sobre as respostas JSON retornadas na seção Testar a API Web:
- O uso de maiúsculas e minúsculas padrão dos nomes da propriedade deve ser alterado para corresponder ao uso de maiúsculas e minúsculas Pascal dos nomes de propriedade do objeto CLR.
- A propriedade
bookName
deve ser retornada comoName
.
Para cumprir os requisitos anteriores, faça as seguintes alterações:
Em
Program.cs
, encadeie o seguinte código realçado para a chamada de métodoAddControllers
:var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.Configure<BookStoreDatabaseSettings>( builder.Configuration.GetSection("BookStoreDatabase")); builder.Services.AddSingleton<BooksService>(); builder.Services.AddControllers() .AddJsonOptions( options => options.JsonSerializerOptions.PropertyNamingPolicy = null);
Com a alteração anterior, os nomes de propriedade na resposta JSON serializada da API Web correspondem aos respectivos nomes de propriedade no tipo de objeto CLR. Por exemplo, a propriedade
Author
da classeBook
é serializada comoAuthor
ao invés deauthor
.No
Models/Book.cs
, anote a propriedadeBookName
com o atributo[JsonPropertyName]
:[BsonElement("Name")] [JsonPropertyName("Name")] public string BookName { get; set; } = null!;
O valor do atributo
[JsonPropertyName]
deName
representa o nome da propriedade da resposta JSON serializada da API Web.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;
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:
- Microsoft Entra ID
- Azure Active Directory B2C (Azure AD B2C)
- Duende Identity Server
O Duende Identity Server é uma estrutura do OpenID Connect e OAuth 2.0 para ASP.NET Core. O Duende Identity Server habilita os seguintes recursos de segurança:
- AaaS (autenticação como serviço)
- SSO (logon único) em vários tipos de aplicativo
- Controle de acesso para APIs
- Federation Gateway
Importante
O Software Duende pode exigir que você pague uma taxa de licença pelo uso de produção do Duende Identity Server. Para obter mais informações, consulte Migrar do ASP.NET Core 5.0 para o 6.0.
Para obter mais informações, confira a documentação do Duende Identity Server (site da Duende Software).
Recursos adicionais
Este tutorial cria uma API Web que executa as operações CRUD (criar, ler, atualizar e excluir) em um banco de dados NoSQL do MongoDB.
Neste tutorial, você aprenderá como:
- Configurar o MongoDB
- Criar um banco de dados do MongoDB
- Definir uma coleção e um esquema do MongoDB
- Executar operações CRUD do MongoDB a partir de uma API Web
- Personalizar a serialização JSON
Pré-requisitos
- Visual Studio 2022 com a carga de trabalho do ASP.NET e desenvolvimento Web.
- SDK do .NET 6.0
Configurar o MongoDB
Habilite o acesso ao Shell do MongoDB e do Mongo DB de qualquer lugar no computador de desenvolvimento:
Se você usar o Windows, o MongoDB será instalado em C:\Arquivos de Programas\MongoDB por padrão. Adicione C:\Arquivos de Programas\MongoDB\Server<número_de_versão>>\bin à variável de ambiente
PATH
.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 ambientePATH
.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.
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
.
Abra uma instância do shell de comando do MongoDB iniciando
mongosh.exe
.Conecte-se ao banco de dados de testes padrão executando o seguinte comando no shell de comando:
mongosh
Execute o seguinte comando no shell de comando:
use BookStore
Um banco de dados chamado BookstoreDb será criado se ele já não existir. Se o banco de dados existir, a conexão dele será aberta para transações.
Crie uma coleção
Books
usando o seguinte comando:db.createCollection('Books')
O seguinte resultado é exibido:
{ "ok" : 1 }
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
ObjectId
s mostrados no resultado anterior não corresponderão aos mostrados no shell de comando.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 tipoObjectId
para cada documento.
Criar o projeto da API Web do ASP.NET Core
Acesse Arquivo>Novo>Projeto.
Selecione o tipo do projeto da API Web do ASP.NET Core e, em seguida, Avançar.
Nomeie o projeto como BookStoreApi e clique em Avançar.
Selecione a estrutura .NET 6.0 (suporte de longo prazo) e selecione Criar.
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
Adicione um diretório Modelos à raiz do projeto.
Adicione uma classe
Book
ao diretório Modelos com o seguinte código:using MongoDB.Bson; using MongoDB.Bson.Serialization.Attributes; namespace BookStoreApi.Models; public class Book { [BsonId] [BsonRepresentation(BsonType.ObjectId)] public string? Id { get; set; } [BsonElement("Name")] public string BookName { get; set; } = null!; public decimal Price { get; set; } public string Category { get; set; } = null!; public string Author { get; set; } = null!; }
Na classe anterior, a propriedade
Id
é:- Necessária para mapear o objeto CLR (Common Language Runtime) para a coleção do MongoDB.
- Anotada com
[BsonId]
para designar essa propriedade como a chave primária do documento. - Anotada com
[BsonRepresentation(BsonType.ObjectId)]
para permitir a passagem do parâmetro como tipostring
, em vez de uma estrutura ObjectId. O Mongo processa a conversão destring
paraObjectId
.
A propriedade
BookName
é anotada com o atributo[BsonElement]
. O valor do atributo deName
representa o nome da propriedade da coleção do MongoDB.
Adicionar um modelo de configuração
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": "*" }
Adicione uma classe
BookStoreDatabaseSettings
ao diretório Modelos com o seguinte código:namespace BookStoreApi.Models; public class BookStoreDatabaseSettings { public string ConnectionString { get; set; } = null!; public string DatabaseName { get; set; } = null!; public string BooksCollectionName { get; set; } = null!; }
A classe anterior
BookStoreDatabaseSettings
é usada para armazenar os valores de propriedadeBookStoreDatabase
do arquivoappsettings.json
. Os nomes de propriedade JSON e C# são nomeados de forma idêntica para facilitar o processo de mapeamento.Adicione o código realçado a seguir a
Program.cs
:var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.Configure<BookStoreDatabaseSettings>( builder.Configuration.GetSection("BookStoreDatabase"));
No código anterior, a instância de configuração à qual a seção
BookStoreDatabase
do arquivoappsettings.json
é registrada no contêiner de DI (Injeção de Dependência). Por exemplo, a propriedadeConnectionString
de um objetoBookStoreDatabaseSettings
é populada com a propriedadeBookStoreDatabase:ConnectionString
noappsettings.json
.Adicione o seguinte código na parte superior do
Program.cs
para resolver a referênciaBookStoreDatabaseSettings
:using BookStoreApi.Models;
Adicionar um serviço de operações CRUD
Adicione um diretório Serviços à raiz do projeto.
Adicione uma classe
BooksService
ao diretório Serviços com o seguinte código:using BookStoreApi.Models; using Microsoft.Extensions.Options; using MongoDB.Driver; namespace BookStoreApi.Services; public class BooksService { private readonly IMongoCollection<Book> _booksCollection; public BooksService( IOptions<BookStoreDatabaseSettings> bookStoreDatabaseSettings) { var mongoClient = new MongoClient( bookStoreDatabaseSettings.Value.ConnectionString); var mongoDatabase = mongoClient.GetDatabase( bookStoreDatabaseSettings.Value.DatabaseName); _booksCollection = mongoDatabase.GetCollection<Book>( bookStoreDatabaseSettings.Value.BooksCollectionName); } public async Task<List<Book>> GetAsync() => await _booksCollection.Find(_ => true).ToListAsync(); public async Task<Book?> GetAsync(string id) => await _booksCollection.Find(x => x.Id == id).FirstOrDefaultAsync(); public async Task CreateAsync(Book newBook) => await _booksCollection.InsertOneAsync(newBook); public async Task UpdateAsync(string id, Book updatedBook) => await _booksCollection.ReplaceOneAsync(x => x.Id == id, updatedBook); public async Task RemoveAsync(string id) => await _booksCollection.DeleteOneAsync(x => x.Id == id); }
No código anterior, uma instância
BookStoreDatabaseSettings
é recuperada da DI por meio da injeção de construtor. Essa técnica fornece acesso para os valores de configuração doappsettings.json
que foram adicionados na seção Adicionar um modelo de configuração.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 porqueBooksService
usa uma dependência direta deMongoClient
. De acordo com as Diretrizes oficiais de reutilização do cliente Mongo, oMongoClient
deve ser registrado na DI com um tempo de vida do serviço singleton.Adicione o seguinte código na parte superior do
Program.cs
para resolver a referênciaBooksService
:using BookStoreApi.Services;
A classe BooksService
usa os seguintes membros MongoDB.Driver
para executar operações CRUD em relação ao banco de dados:
MongoClient: lê a instância do servidor para executar operações de banco de dados. O construtor dessa classe é fornecido na cadeia de conexão do MongoDB:
public BooksService( IOptions<BookStoreDatabaseSettings> bookStoreDatabaseSettings) { var mongoClient = new MongoClient( bookStoreDatabaseSettings.Value.ConnectionString); var mongoDatabase = mongoClient.GetDatabase( bookStoreDatabaseSettings.Value.DatabaseName); _booksCollection = mongoDatabase.GetCollection<Book>( bookStoreDatabaseSettings.Value.BooksCollectionName); }
IMongoDatabase: representa o banco de dados Mongo para execução de operações. Este tutorial usa o método GetCollection<TDocument>(coleção) genérico na interface para obter acesso aos dados em uma coleção específica. Execute operações CRUD em relação à coleção depois que esse método for chamado. Na chamada de método
GetCollection<TDocument>(collection)
:collection
representa o nome da coleção.TDocument
representa o tipo de objeto CLR armazenado na coleção.
GetCollection<TDocument>(collection)
retorna um objeto MongoCollection que representa a coleção. Neste tutorial, os seguintes métodos são invocados na coleção:
- DeleteOneAsync: exclui um único documento que corresponde aos critérios de pesquisa fornecidos.
- Encontrar<TDocument>: retorna todos os documentos na coleção que correspondem aos critérios de pesquisa fornecidos.
- InsertOneAsync: insere o objeto fornecido como um novo documento na coleção.
- ReplaceOneAsync: substitui o único documento que corresponde aos critérios de pesquisa fornecidos com o objeto fornecido.
Adicionar um controlador
Adicione uma classe BooksController
ao diretório Controladores com o seguinte código:
using BookStoreApi.Models;
using BookStoreApi.Services;
using Microsoft.AspNetCore.Mvc;
namespace BookStoreApi.Controllers;
[ApiController]
[Route("api/[controller]")]
public class BooksController : ControllerBase
{
private readonly BooksService _booksService;
public BooksController(BooksService booksService) =>
_booksService = booksService;
[HttpGet]
public async Task<List<Book>> Get() =>
await _booksService.GetAsync();
[HttpGet("{id:length(24)}")]
public async Task<ActionResult<Book>> Get(string id)
{
var book = await _booksService.GetAsync(id);
if (book is null)
{
return NotFound();
}
return book;
}
[HttpPost]
public async Task<IActionResult> Post(Book newBook)
{
await _booksService.CreateAsync(newBook);
return CreatedAtAction(nameof(Get), new { id = newBook.Id }, newBook);
}
[HttpPut("{id:length(24)}")]
public async Task<IActionResult> Update(string id, Book updatedBook)
{
var book = await _booksService.GetAsync(id);
if (book is null)
{
return NotFound();
}
updatedBook.Id = book.Id;
await _booksService.UpdateAsync(id, updatedBook);
return NoContent();
}
[HttpDelete("{id:length(24)}")]
public async Task<IActionResult> Delete(string id)
{
var book = await _booksService.GetAsync(id);
if (book is null)
{
return NotFound();
}
await _booksService.RemoveAsync(id);
return NoContent();
}
}
O controlador da API Web anterior:
- Usa a classe
BooksService
para executar operações CRUD. - Contém métodos de ação para dar suporte a solicitações GET, POST, PUT e DELETE HTTP.
- Chama o CreatedAtAction no método de ação
Create
para retornar uma resposta HTTP 201. O código de status 201 é a resposta padrão para um método HTTP POST que cria um recurso no servidor.CreatedAtAction
também adiciona um cabeçalhoLocation
à resposta. O cabeçalhoLocation
especifica o URI do livro recém-criado.
Testar a API Web
Compile e execute o aplicativo.
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çãoGet
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" } ]
Navegue até
https://localhost:<port>/api/books/{id here}
para testar o método de açãoGet
sobrecarregado do controlador. Uma resposta JSON semelhante à apresentada a seguir será exibida:{ "id": "61a6058e6c43f32854e51f52", "bookName": "Clean Code", "price": 43.15, "category": "Computers", "author": "Robert C. Martin" }
Configurar opções de serialização JSON
Há dois detalhes alterar sobre as respostas JSON retornadas na seção Testar a API Web:
- O uso de maiúsculas e minúsculas padrão dos nomes da propriedade deve ser alterado para corresponder ao uso de maiúsculas e minúsculas Pascal dos nomes de propriedade do objeto CLR.
- A propriedade
bookName
deve ser retornada comoName
.
Para cumprir os requisitos anteriores, faça as seguintes alterações:
Em
Program.cs
, encadeie o seguinte código realçado para a chamada de métodoAddControllers
:var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.Configure<BookStoreDatabaseSettings>( builder.Configuration.GetSection("BookStoreDatabase")); builder.Services.AddSingleton<BooksService>(); builder.Services.AddControllers() .AddJsonOptions( options => options.JsonSerializerOptions.PropertyNamingPolicy = null);
Com a alteração anterior, os nomes de propriedade na resposta JSON serializada da API Web correspondem aos respectivos nomes de propriedade no tipo de objeto CLR. Por exemplo, a propriedade
Author
da classeBook
é serializada comoAuthor
ao invés deauthor
.No
Models/Book.cs
, anote a propriedadeBookName
com o atributo[JsonPropertyName]
:[BsonElement("Name")] [JsonPropertyName("Name")] public string BookName { get; set; } = null!;
O valor do atributo
[JsonPropertyName]
deName
representa o nome da propriedade da resposta JSON serializada da API Web.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;
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:
- Microsoft Entra ID
- Azure Active Directory B2C (Azure AD B2C)
- Duende Identity Server
O Duende Identity Server é uma estrutura do OpenID Connect e OAuth 2.0 para ASP.NET Core. O Duende Identity Server habilita os seguintes recursos de segurança:
- AaaS (autenticação como serviço)
- SSO (logon único) em vários tipos de aplicativo
- Controle de acesso para APIs
- Federation Gateway
Importante
O Software Duende pode exigir que você pague uma taxa de licença pelo uso de produção do Duende Identity Server. Para obter mais informações, consulte Migrar do ASP.NET Core 5.0 para o 6.0.
Para obter mais informações, confira a documentação do Duende Identity Server (site da Duende Software).
Recursos adicionais
Este tutorial cria uma API Web que executa as operações CRUD (criar, ler, atualizar e excluir) em um banco de dados NoSQL do MongoDB.
Neste tutorial, você aprenderá como:
- Configurar o MongoDB
- Criar um banco de dados do MongoDB
- Definir uma coleção e um esquema do MongoDB
- Executar operações CRUD do MongoDB a partir de uma API Web
- Personalizar a serialização JSON
Exibir ou baixar código de exemplo (como baixar)
Pré-requisitos
- SDK do .NET Core 3.0 ou posterior
- Visual Studio 2019 com carga de trabalho ASP.NET e desenvolvimento Web
- MongoDB
Configurar o MongoDB
Se você usar o Windows, o MongoDB será instalado em C:\Arquivos de Programas\MongoDB por padrão. Adicione C:\Arquivos de Programas\MongoDB\Server<número_de_versão>\bin à variável de ambiente Path
. Essa alteração possibilita o acesso ao MongoDB a partir de qualquer lugar em seu computador de desenvolvimento.
Use o Shell do mongo nas etapas a seguir para criar um banco de dados, fazer coleções e armazenar documentos. Para saber mais sobre os comandos de Shell do mongo, consulte Como trabalhar com o Shell do mongo.
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.
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>
Abra outra instância do shell de comando. Conecte-se ao banco de dados de testes padrão executando o seguinte comando:
mongo
Execute o seguinte comando em um shell de comando:
use BookstoreDb
Se ele ainda não existir, um banco de dados chamado BookstoreDb será criado. Se o banco de dados existir, a conexão dele será aberta para transações.
Crie uma coleção
Books
usando o seguinte comando:db.createCollection('Books')
O seguinte resultado é exibido:
{ "ok" : 1 }
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.
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 tipoObjectId
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
Acesse Arquivo>Novo>Projeto.
Selecione o tipo de projeto aplicativo Web ASP.NET Core e, em seguida, Avançar.
Nomeie o projeto como BooksApi e selecione criar.
Selecione a estrutura de destino .NET Core e ASP.NET Core 3.0. Selecione o modelo de projeto API e, em seguida, Criar.
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
Adicione um diretório Modelos à raiz do projeto.
Adicione uma classe
Book
ao diretório Modelos com o seguinte código:using MongoDB.Bson; using MongoDB.Bson.Serialization.Attributes; namespace BooksApi.Models { public class Book { [BsonId] [BsonRepresentation(BsonType.ObjectId)] public string Id { get; set; } [BsonElement("Name")] public string BookName { get; set; } public decimal Price { get; set; } public string Category { get; set; } public string Author { get; set; } } }
Na classe anterior, a propriedade
Id
é:- Necessária para mapear o objeto CLR (Common Language Runtime) para a coleção do MongoDB.
- Anotada com
[BsonId]
para designar essa propriedade como a chave primária do documento. - Anotada com
[BsonRepresentation(BsonType.ObjectId)]
para permitir a passagem do parâmetro como tipostring
, em vez de uma estrutura ObjectId. O Mongo processa a conversão destring
paraObjectId
.
A propriedade
BookName
é anotada com o atributo[BsonElement]
. O valor do atributo deName
representa o nome da propriedade da coleção do MongoDB.
Adicionar um modelo de configuração
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" } } } }
Adicione uma classe
BookstoreDatabaseSettings.cs
ao diretório Modelos com o seguinte código:namespace BooksApi.Models { public class BookstoreDatabaseSettings : IBookstoreDatabaseSettings { public string BooksCollectionName { get; set; } public string ConnectionString { get; set; } public string DatabaseName { get; set; } } public interface IBookstoreDatabaseSettings { string BooksCollectionName { get; set; } string ConnectionString { get; set; } string DatabaseName { get; set; } } }
A classe anterior
BookstoreDatabaseSettings
é usada para armazenar os valores de propriedadeBookstoreDatabaseSettings
do arquivoappsettings.json
. Os nomes de propriedade JSON e C# são nomeados de forma idêntica para facilitar o processo de mapeamento.Adicione o código realçado a seguir a
Startup.ConfigureServices
:public void ConfigureServices(IServiceCollection services) { // requires using Microsoft.Extensions.Options services.Configure<BookstoreDatabaseSettings>( Configuration.GetSection(nameof(BookstoreDatabaseSettings))); services.AddSingleton<IBookstoreDatabaseSettings>(sp => sp.GetRequiredService<IOptions<BookstoreDatabaseSettings>>().Value); services.AddControllers(); }
No código anterior:
- A instância de configuração à qual a seção
BookstoreDatabaseSettings
do arquivoappsettings.json
é associada é registrada no contêiner de DI (Injeção de Dependência). Por exemplo, a propriedadeConnectionString
de um objetoBookstoreDatabaseSettings
é populada com a propriedadeBookstoreDatabaseSettings:ConnectionString
noappsettings.json
. - A interface
IBookstoreDatabaseSettings
é registrada na DI com um tempo de vida do serviço singleton. Quando inserida, a instância da interface é resolvida para um objetoBookstoreDatabaseSettings
.
- A instância de configuração à qual a seção
Adicione o seguinte código na parte superior do
Startup.cs
para resolver as referênciasBookstoreDatabaseSettings
eIBookstoreDatabaseSettings
:using BooksApi.Models;
Adicionar um serviço de operações CRUD
Adicione um diretório Serviços à raiz do projeto.
Adicione uma classe
BookService
ao diretório Serviços com o seguinte código:using BooksApi.Models; using MongoDB.Driver; using System.Collections.Generic; using System.Linq; namespace BooksApi.Services { public class BookService { private readonly IMongoCollection<Book> _books; public BookService(IBookstoreDatabaseSettings settings) { var client = new MongoClient(settings.ConnectionString); var database = client.GetDatabase(settings.DatabaseName); _books = database.GetCollection<Book>(settings.BooksCollectionName); } public List<Book> Get() => _books.Find(book => true).ToList(); public Book Get(string id) => _books.Find<Book>(book => book.Id == id).FirstOrDefault(); public Book Create(Book book) { _books.InsertOne(book); return book; } public void Update(string id, Book bookIn) => _books.ReplaceOne(book => book.Id == id, bookIn); public void Remove(Book bookIn) => _books.DeleteOne(book => book.Id == bookIn.Id); public void Remove(string id) => _books.DeleteOne(book => book.Id == id); } }
No código anterior, uma instância
IBookstoreDatabaseSettings
é recuperada da DI por meio da injeção de construtor. Essa técnica fornece acesso para os valores de configuração doappsettings.json
que foram adicionados na seção Adicionar um modelo de configuração.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 porqueBookService
usa uma dependência direta deMongoClient
. De acordo com as Diretrizes oficiais de reutilização do cliente Mongo, oMongoClient
deve ser registrado na DI com um tempo de vida do serviço singleton.Adicione o seguinte código na parte superior do
Startup.cs
para resolver a referênciaBookService
:using BooksApi.Services;
A classe BookService
usa os seguintes membros MongoDB.Driver
para executar operações CRUD em relação ao banco de dados:
MongoClient: lê a instância do servidor para executar operações de banco de dados. O construtor dessa classe é fornecido na cadeia de conexão do MongoDB:
public BookService(IBookstoreDatabaseSettings settings) { var client = new MongoClient(settings.ConnectionString); var database = client.GetDatabase(settings.DatabaseName); _books = database.GetCollection<Book>(settings.BooksCollectionName); }
IMongoDatabase: representa o banco de dados Mongo para execução de operações. Este tutorial usa o método GetCollection<TDocument>(coleção) genérico na interface para obter acesso aos dados em uma coleção específica. Execute operações CRUD em relação à coleção depois que esse método for chamado. Na chamada de método
GetCollection<TDocument>(collection)
:collection
representa o nome da coleção.TDocument
representa o tipo de objeto CLR armazenado na coleção.
GetCollection<TDocument>(collection)
retorna um objeto MongoCollection que representa a coleção. Neste tutorial, os seguintes métodos são invocados na coleção:
- DeleteOne: exclui um único documento que corresponde aos critérios de pesquisa fornecidos.
- Find<TDocument>> retorna todos os documentos na coleção que correspondem aos critérios de pesquisa fornecidos.
- InsertOne: insere o objeto fornecido como um novo documento na coleção.
- ReplaceOne: substitui o único documento que corresponde aos critérios de pesquisa fornecidos com o objeto fornecido.
Adicionar um controlador
Adicione uma classe BooksController
ao diretório Controladores com o seguinte código:
using BooksApi.Models;
using BooksApi.Services;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
namespace BooksApi.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class BooksController : ControllerBase
{
private readonly BookService _bookService;
public BooksController(BookService bookService)
{
_bookService = bookService;
}
[HttpGet]
public ActionResult<List<Book>> Get() =>
_bookService.Get();
[HttpGet("{id:length(24)}", Name = "GetBook")]
public ActionResult<Book> Get(string id)
{
var book = _bookService.Get(id);
if (book == null)
{
return NotFound();
}
return book;
}
[HttpPost]
public ActionResult<Book> Create(Book book)
{
_bookService.Create(book);
return CreatedAtRoute("GetBook", new { id = book.Id.ToString() }, book);
}
[HttpPut("{id:length(24)}")]
public IActionResult Update(string id, Book bookIn)
{
var book = _bookService.Get(id);
if (book == null)
{
return NotFound();
}
_bookService.Update(id, bookIn);
return NoContent();
}
[HttpDelete("{id:length(24)}")]
public IActionResult Delete(string id)
{
var book = _bookService.Get(id);
if (book == null)
{
return NotFound();
}
_bookService.Remove(id);
return NoContent();
}
}
}
O controlador da API Web anterior:
- Usa a classe
BookService
para executar operações CRUD. - Contém métodos de ação para dar suporte a solicitações GET, POST, PUT e DELETE HTTP.
- Chama o CreatedAtRoute no método de ação
Create
para retornar uma resposta HTTP 201. O código de status 201 é a resposta padrão para um método HTTP POST que cria um recurso no servidor.CreatedAtRoute
também adiciona um cabeçalhoLocation
à resposta. O cabeçalhoLocation
especifica o URI do livro recém-criado.
Testar a API Web
Compile e execute o aplicativo.
Navegue até
https://localhost:<port>/api/books
para testar o método de açãoGet
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" } ]
Navegue até
https://localhost:<port>/api/books/{id here}
para testar o método de açãoGet
sobrecarregado do controlador. A seguinte resposta JSON é exibida:{ "id":"{ID}", "bookName":"Clean Code", "price":43.15, "category":"Computers", "author":"Robert C. Martin" }
Configurar opções de serialização JSON
Há dois detalhes alterar sobre as respostas JSON retornadas na seção Testar a API Web:
- O uso de maiúsculas e minúsculas padrão dos nomes da propriedade deve ser alterado para corresponder ao uso de maiúsculas e minúsculas Pascal dos nomes de propriedade do objeto CLR.
- A propriedade
bookName
deve ser retornada comoName
.
Para cumprir os requisitos anteriores, faça as seguintes alterações:
O JSON.NET foi removido da estrutura compartilhada do ASP.NET. Adicione uma referência de pacote para
Microsoft.AspNetCore.Mvc.NewtonsoftJson
.Em
Startup.ConfigureServices
, encadeie o seguinte código realçado para a chamada de métodoAddControllers
:public void ConfigureServices(IServiceCollection services) { services.Configure<BookstoreDatabaseSettings>( Configuration.GetSection(nameof(BookstoreDatabaseSettings))); services.AddSingleton<IBookstoreDatabaseSettings>(sp => sp.GetRequiredService<IOptions<BookstoreDatabaseSettings>>().Value); services.AddSingleton<BookService>(); services.AddControllers() .AddNewtonsoftJson(options => options.UseMemberCasing()); }
Com a alteração anterior, os nomes de propriedade na resposta JSON serializada da API Web correspondem aos respectivos nomes de propriedade no tipo de objeto CLR. Por exemplo, a propriedade
Author
da classeBook
é serializada comoAuthor
.No
Models/Book.cs
, anote a propriedadeBookName
com o atributo[JsonProperty]
a seguir:[BsonElement("Name")] [JsonProperty("Name")] public string BookName { get; set; }
O valor do atributo
[JsonProperty]
deName
representa o nome da propriedade da resposta JSON serializada da API Web.Adicione o seguinte código na parte superior do
Models/Book.cs
para resolver a referência[JsonProperty]
do atributo:using Newtonsoft.Json;
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:
- Microsoft Entra ID
- Azure Active Directory B2C (Azure AD B2C)
- IdentityServer da Duende. O IdentityServer da Duende é um produto de terceiros.
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
- Federation Gateway
Para obter mais informações, consulte Visão geral do IdentityServer da Duende.
Para obter mais informações sobre outros provedores de autenticação, consulte Opções de autenticação de OSS da comunidade para ASP.NET Core
Próximas etapas
Para saber mais sobre a criação de APIs Web do ASP.NET Core, confira os seguintes recursos: