Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
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 Tim Deschryver e Rick Anderson
Este tutorial ensina os conceitos básicos da criação de uma API Web baseada em controlador que usa um banco de dados. Outra abordagem para criar APIs no ASP.NET Core é criar APIs mínimas. Para obter ajuda na escolha entre APIs mínimas e APIs baseadas em controlador, veja Visão geral de APIs. Para obter um tutorial sobre como criar uma API mínima, confira Tutorial: Criar uma API mínima com ASP.NET Core.
Visão geral
Este tutorial cria a seguinte API:
Interface de Programação de Aplicativos (API) | Descrição | Corpo da solicitação | Corpo da resposta |
---|---|---|---|
GET /api/todoitems |
Obter todos os itens de tarefas pendentes | Nenhum | Matriz de itens de tarefas pendentes |
GET /api/todoitems/{id} |
Obter um item por ID | Nenhum | Item de tarefas pendentes |
POST /api/todoitems |
Adicionar um novo item | Item de tarefas pendentes | Item de tarefas pendentes |
PUT /api/todoitems/{id} |
Atualizar um item existente | Item de tarefas pendentes | Nenhum |
DELETE /api/todoitems/{id} |
Excluir um item | Nenhum | Nenhum |
O diagrama a seguir mostra o design do aplicativo.
Pré-requisitos
Visual Studio 2022 com a carga de trabalho de desenvolvimento Web e do ASP.NET.
Criar um projeto de API Web
- No menu Arquivo, selecione Novo>Projeto.
- Insira API Web na caixa de pesquisa.
- Selecione o modelo API Web do ASP.NET Core e Avançar.
- Na caixa de diálogo Configurar o novo projeto, nomeie o projeto TodoApi e selecione Avançar.
- Na caixa de diálogo Informações adicionais:
- Confirme se o Framework é o .NET 9.0 (suporte de prazo padrão).
- Confirme se a caixa de seleção Habilitar suporte a OpenAPI está marcada.
- Confirme se a caixa de seleção Usar controladores (desmarque para utilizar APIs mínimas) está marcada.
- Selecione Criar.
Adicionar um pacote NuGet
Um pacote NuGet deve ser adicionado para suportar o banco de dados utilizado neste tutorial.
- No menu Ferramentas, selecione Gerenciador de Pacotes do NuGet > Gerenciar Pacotes do NuGet para a Solução.
- Selecione a guia Navegar.
- Na caixa de pesquisa, insira Microsoft.EntityFrameworkCore.InMemory e selecione
Microsoft.EntityFrameworkCore.InMemory
. - Marque a caixa de seleção Projeto no painel direito e selecione Instalar.
Observação
Para obter diretrizes sobre como adicionar pacotes a aplicativos .NET, consulte os artigos em Instalar e gerenciar pacotes no Fluxo de trabalho de consumo de pacotes (documentação do NuGet). Confirme as versões corretas de pacote em NuGet.org.
Executar o projeto
O modelo de projeto cria uma API WeatherForecast
com suporte para OpenAPI.
Pressione Ctrl + F5 para execução sem o depurador.
O Visual Studio exibe a seguinte caixa de diálogo quando um projeto ainda não está configurado para usar o SSL:
Selecione Sim se você confia no certificado SSL do IIS Express.
A seguinte caixa de diálogo é exibida:
Selecione Sim se você concordar com confiar no certificado de desenvolvimento.
Para obter informações sobre como confiar no navegador Firefox, confira Erro de certificado Firefox SEC_ERROR_INADEQUATE_KEY_USAGE.
O Visual Studio inicia uma janela de terminal e exibe a URL do aplicativo em execução. A API é hospedada em https://localhost:<port>
, em que <port>
é um conjunto de números de porta escolhido aleatoriamente na criação do projeto.
...
info: Microsoft.Hosting.Lifetime[14]
Now listening on: https://localhost:7260
info: Microsoft.Hosting.Lifetime[14]
Now listening on: http://localhost:7261
info: Microsoft.Hosting.Lifetime[0]
Application started. Press Ctrl+C to shut down.
...
Ctrl+clique na URL HTTPS na saída para testar o aplicativo Web em um navegador. Não existe um ponto de extremidade em https://localhost:<port>
, portanto, o navegador retorna HTTP 404 Não encontrado.
Acrescente /weatherforecast
à URL para testar a API WeatherForecast.
O navegador exibe JSON semelhante ao seguinte exemplo:
[
{
"date": "2025-07-16",
"temperatureC": 52,
"temperatureF": 125,
"summary": "Mild"
},
{
"date": "2025-07-17",
"temperatureC": 36,
"temperatureF": 96,
"summary": "Warm"
},
{
"date": "2025-07-18",
"temperatureC": 39,
"temperatureF": 102,
"summary": "Cool"
},
{
"date": "2025-07-19",
"temperatureC": 10,
"temperatureF": 49,
"summary": "Bracing"
},
{
"date": "2025-07-20",
"temperatureC": -1,
"temperatureF": 31,
"summary": "Chilly"
}
]
Testar o projeto
Este tutorial usa arquivos do Endpoints Explorer e .http para testar a API.
Adicionar uma classe de modelo
Um modelo é um conjunto de classes que representam os dados gerenciados pelo aplicativo. O modelo para este aplicativo é a classe TodoItem
.
- No Gerenciador de Soluções, clique com o botão direito do mouse no nome do projeto. Selecione Adicionar>nova pasta. Nomeie a pasta
Models
. - Clique com o botão direito do mouse na pasta
Models
e selecione Adicionar>Classe. Dê à classe o nome TodoItem e selecione Adicionar. - Substitua o código do modelo pelo seguinte:
namespace TodoApi.Models;
public class TodoItem
{
public long Id { get; set; }
public string? Name { get; set; }
public bool IsComplete { get; set; }
}
A propriedade Id
funciona como a chave exclusiva em um banco de dados relacional.
As classes de modelo podem ser colocadas em qualquer lugar no projeto, mas a pasta Models
é usada por convenção.
Adicionar um contexto de banco de dados
O contexto de banco de dados é a classe principal que coordena a funcionalidade do Entity Framework para um modelo de dados. Essa classe é criada derivando-a da classe Microsoft.EntityFrameworkCore.DbContext.
Clique com o botão direito do mouse na pasta
Models
e selecione Adicionar>Classe. Nomeie a classe como TodoContext e clique em Adicionar.Insira o seguinte código:
using Microsoft.EntityFrameworkCore; namespace TodoApi.Models; public class TodoContext : DbContext { public TodoContext(DbContextOptions<TodoContext> options) : base(options) { } public DbSet<TodoItem> TodoItems { get; set; } = null!; }
Registrar o contexto de banco de dados
No ASP.NET Core, serviços como o contexto do banco de dados precisam ser registrados no contêiner de injeção de dependência (DI). O contêiner fornece o serviço aos controladores.
Atualize Program.cs
com o seguinte código realçado:
using Microsoft.EntityFrameworkCore;
using TodoApi.Models;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddOpenApi();
builder.Services.AddDbContext<TodoContext>(opt =>
opt.UseInMemoryDatabase("TodoList"));
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.MapOpenApi();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
O código anterior:
- Adiciona diretivas
using
. - Adiciona o contexto de banco de dados ao contêiner de DI.
- Especifica que o contexto de banco de dados usará um banco de dados em memória.
Faça scaffold de um controlador
Clique com o botão direito do mouse na pasta
Controllers
.Selecione Adicionar>New Scaffolded Item.
Selecione Controlador de API com ações, usando o Entity Framework e, em seguida, selecione Adicionar.
Na caixa de diálogo Adicionar Controlador de API com ações, usando o Entity Framework:
- Selecione TodoItem (TodoApi.Models) na classe Modelo.
- Selecione TodoContext (TodoApi.Models) na classe Contexto de Dados.
- Selecione Adicionar.
Se a operação de scaffolding falhar, selecione Adicionar para tentar estruturar uma segunda vez.
Esta etapa adiciona os pacotes NuGet Microsoft.VisualStudio.Web.CodeGeneration.Design
e Microsoft.EntityFrameworkCore.Tools
ao projeto.
Esses pacotes são necessários para a estrutura.
O código gerado:
- Marca a classe com o atributo
[ApiController]
. Esse atributo indica se o controlador responde às solicitações da API Web. Para obter informações sobre comportamentos específicos habilitados pelo atributo, confira Criar APIs Web com o ASP.NET Core. - Usa a DI para injetar o contexto de banco de dados (
TodoContext
) no controlador. O contexto de banco de dados é usado em cada um dos métodos CRUD no controlador.
Os modelos do ASP.NET Core para:
- Os controladores com exibições incluem
[action]
no modelo de rota. - Os controladores de API não incluem
[action]
no modelo de rota.
Quando o token [action]
não estiver no modelo de rota, o nome da ação (nome do método) não está incluído no ponto de extremidade. Ou seja, o nome do método associado da ação não é usado na rota correspondente.
Atualize o método PostTodoItem create
Atualize a instrução return no PostTodoItem
para usar o operador nameof:
[HttpPost]
public async Task<ActionResult<TodoItem>> PostTodoItem(TodoItem todoItem)
{
_context.TodoItems.Add(todoItem);
await _context.SaveChangesAsync();
// return CreatedAtAction("GetTodoItem", new { id = todoItem.Id }, todoItem);
return CreatedAtAction(nameof(GetTodoItem), new { id = todoItem.Id }, todoItem);
}
O código anterior é um método HTTP POST
, conforme indicado pelo atributo [HttpPost]
. O método obtém o valor do TodoItem
no corpo da solicitação HTTP.
Para obter mais informações, confira Roteamento de atributo com atributos Http[Verb].
O método CreatedAtAction:
- Retorna um código de status HTTP 201 em caso de êxito.
HTTP 201
é a resposta padrão para um métodoHTTP POST
que cria um recurso no servidor. - Adiciona um cabeçalho de Local à resposta. O cabeçalho
Location
especifica o URI do item de tarefas pendentes recém-criado. Para obter mais informações, confira 10.2.2 201 Criado. - Faz referência à ação
GetTodoItem
para criar o URI deLocation
do cabeçalho. A palavra-chavenameof
do C# é usada para evitar o hard-coding do nome da ação, na chamadaCreatedAtAction
.
Testar PostTodoItem
Selecione Exibir>Outras janelas>Gerenciador de pontos de extremidade.
Clique com o botão direito do mouse no ponto de extremidade POST e selecione Gerar solicitação.
Um novo arquivo é criado na pasta de projeto chamada
TodoApi.http
, com conteúdo semelhante ao exemplo a seguir:@TodoApi_HostAddress = https://localhost:49738 POST {{TodoApi_HostAddress}}/api/todoitems Content-Type: application/json { //TodoItem } ###
- A primeira linha cria uma variável que é usada para todos os pontos de extremidade.
- A próxima linha define uma solicitação POST.
- As linhas após a linha de solicitação POST definem os cabeçalhos e um espaço reservado para o corpo da solicitação.
- A linha de hashtag tripla (
###
) é um delimitador de solicitação: o que segue depois dela se refere a uma solicitação diferente.
A solicitação POST espera um
TodoItem
. Para definir o todo, substitua o comentário//TodoItem
pelo seguinte JSON:{ "name": "walk dog", "isComplete": true }
O arquivo TodoApi.http agora deve estar similar ao exemplo a seguir, mas com o seu número de porta:
@TodoApi_HostAddress = https://localhost:7260 Post {{TodoApi_HostAddress}}/api/todoitems Content-Type: application/json { "name": "walk dog", "isComplete": true } ###
Execute o aplicativo.
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.
Testar o URI do cabeçalho de local
Teste o aplicativo chamando os pontos de extremidade GET
de um navegador ou usando o Gerenciador de Pontos de Extremidade. As etapas a seguir são para o Gerenciador de Pontos de Extremidade.
No Gerenciador de Pontos de Extremidade, clique com o botão direito do mouse no primeiro ponto de extremidade GET e selecione Gerar solicitação.
O seguinte conteúdo é adicionado ao arquivo
TodoApi.http
:GET {{TodoApi_HostAddress}}/api/todoitems ###
Selecione o link Enviar solicitação acima da nova linha de solicitação
GET
.A solicitação GET é enviada ao aplicativo e a resposta é exibida no painel Resposta.
O corpo da resposta é semelhante ao seguinte JSON:
[ { "id": 1, "name": "walk dog", "isComplete": true } ]
No Gerenciador de Pontos de Extremidade, clique com o botão direito do mouse no ponto de extremidade
/api/todoitems/{id}
GET e selecione Gerar solicitação. O seguinte conteúdo é adicionado ao arquivoTodoApi.http
:@id=0 GET {{TodoApi_HostAddress}}/api/todoitems/{{id}} ###
Atribuir
{@id}
a1
(em vez de0
).Selecione o link Enviar solicitação acima da nova linha solicitação GET.
A solicitação GET é enviada ao aplicativo e a resposta é exibida no painel Resposta.
O corpo da resposta é semelhante ao seguinte JSON:
{ "id": 1, "name": "walk dog", "isComplete": true }
Examine os métodos GET
Foram implementados dois endpoints GET:
GET /api/todoitems
GET /api/todoitems/{id}
A seção anterior mostrou um exemplo da rota /api/todoitems/{id}
.
Siga as instruções POST para adicionar outro item todo e teste a rota /api/todoitems
usando o Swagger.
Este aplicativo usa um banco de dados em memória. Se o aplicativo for interrompido e iniciado, a solicitação GET anterior não retornará nenhum dado. Se nenhum dado for retornado, envie dados usando POST para o aplicativo.
Roteamento e caminhos de URL
O atributo [HttpGet]
indica um método que responde a uma solicitação HTTP GET
. O caminho da URL de cada método é construído da seguinte maneira:
Comece com a cadeia de caracteres de modelo no atributo
Route
do controlador:[Route("api/[controller]")] [ApiController] public class TodoItemsController : ControllerBase
Substitua
[controller]
pelo nome do controlador, que é o nome de classe do controlador menos o sufixo "Controlador" por convenção. Para esta amostra, o nome da classe do controlador é TodoItemsController. Portanto, o nome do controlador é "TodoItems". O roteamento do ASP.NET Core não diferencia maiúsculas de minúsculas.Se o atributo
[HttpGet]
tiver um modelo de rota (por exemplo,[HttpGet("products")]
), acrescente isso ao caminho. Esta amostra não usa um modelo. Para obter mais informações, confira Roteamento de atributo com atributos Http[Verb].
No método GetTodoItem
a seguir, "{id}"
é uma variável de espaço reservado para o identificador exclusivo do item pendente. Quando GetTodoItem
é invocado, o valor de "{id}"
na URL é fornecido para o método no parâmetro id
.
[HttpGet("{id}")]
public async Task<ActionResult<TodoItem>> GetTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
return todoItem;
}
Valores retornados
O tipo de retorno dos métodos GetTodoItems
e GetTodoItem
é o tipo <ActionResult>T. O ASP.NET Core serializa automaticamente o objeto em JSON e grava o JSON no corpo da mensagem de resposta. O código de resposta para esse tipo de retorno é 200 OK, supondo que não haja nenhuma exceção sem tratamento. As exceções sem tratamento são convertidas em erros 5xx.
Os tipos de retorno ActionResult
podem representar uma ampla variedade de códigos de status HTTP. Por exemplo, GetTodoItem
pode retornar dois valores de status diferentes:
- Se nenhum item corresponder às ID solicitadas, o método retornará um código de erro status 404NotFound.
- Caso contrário, o método retornará 200 com um corpo de resposta JSON. O retorno de
item
resulta em uma respostaHTTP 200
.
O método PutTodoItem
Examine o método PutTodoItem
:
[HttpPut("{id}")]
public async Task<IActionResult> PutTodoItem(long id, TodoItem todoItem)
{
if (id != todoItem.Id)
{
return BadRequest();
}
_context.Entry(todoItem).State = EntityState.Modified;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!TodoItemExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return NoContent();
}
PutTodoItem
é semelhante a PostTodoItem
, exceto pelo uso de HTTP PUT
. A resposta é 204 (Sem conteúdo). De acordo com a especificação de HTTP, uma solicitação PUT
exige que o cliente envie a entidade inteira atualizada, não apenas as alterações. Para dar suporte a atualizações parciais, use HTTP PATCH.
Testar o método PutTodoItem
Este exemplo usa um banco de dados em memória que precisará ser iniciado sempre que o aplicativo for iniciado. Deverá haver um item no banco de dados antes de você fazer uma chamada PUT. Chame GET para garantir a existência de um item no banco de dados antes de fazer uma chamada PUT.
Use o método PUT
para atualizar o TodoItem
que tem id = 1 e definir seu nome como "feed fish"
. Observe que a resposta é HTTP 204 No Content
.
No Gerenciador de Pontos de Extremidade, clique com o botão direito do mouse no ponto de extremidade PUT e selecione Gerar solicitação.
O seguinte conteúdo é adicionado ao arquivo
TodoApi.http
:PUT {{TodoApi_HostAddress}}/api/todoitems/{{id}} Content-Type: application/json { //TodoItem } ###
Na linha de solicitação PUT, substitua
{{id}}
por1
.Substitua o marcador de posição
//TodoItem
pelas seguintes linhas:PUT {{TodoApi_HostAddress}}/api/todoitems/1 Content-Type: application/json { "id": 1, "name": "feed fish", "isComplete": false }
Selecione o link Enviar solicitação acima da nova linha solicitação PUT.
A solicitação PUT é enviada ao aplicativo e a resposta é exibida no painel Resposta. O corpo da resposta está vazio e o código de status é 204.
O método DeleteTodoItem
Examine o método DeleteTodoItem
:
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
_context.TodoItems.Remove(todoItem);
await _context.SaveChangesAsync();
return NoContent();
}
Testar o método DeleteTodoItem
Use o método DELETE
para excluir o TodoItem
que tem id = 1. Observe que a resposta é HTTP 204 No Content
.
No Gerenciador de Pontos de Extremidade, clique com o botão direito do mouse do ponto de extremidade DELETE e selecione Gerar solicitação.
Uma solicitação DELETE é adicionada a
TodoApi.http
.Substitua
{{id}}
na linha de solicitação DELETE por1
. A solicitação DELETE deve ser semelhante ao exemplo a seguir:DELETE {{TodoApi_HostAddress}}/api/todoitems/{{id}} ###
Selecione o link Enviar solicitação para a solicitação DELETE.
A solicitação DELETE é enviada ao aplicativo e a resposta é exibida no painel Resposta. O corpo da resposta está vazio e o código de status é 204.
Teste com outras ferramentas
Existem muitas outras ferramentas que podem ser utilizadas para testar APIs Web, por exemplo:
- http-repl
-
curl. O Swagger utiliza
curl
e mostra os comandoscurl
que envia. - Violinista
Impedir o excesso de postagem
Atualmente, o aplicativo de exemplo expõe todo o objeto TodoItem
. Os aplicativos de produção normalmente limitam os dados de entrada e saída usando um subconjunto do modelo. Há várias razões por trás disso, e a segurança é uma das principais. O subconjunto de um modelo geralmente é chamado de DTO (Objeto de Transferência de Dados), modelo de entrada ou modelo de exibição. O DTO é usado neste tutorial.
Um DTO pode ser usado para:
- Impedir o excesso de postagem.
- Ocultar propriedades que os clientes não devem visualizar.
- Omitir algumas propriedades para reduzir o tamanho da carga.
- Nivelar gráficos de objetos que contenham objetos aninhados. Os grafos de objeto nivelados podem ser mais convenientes para os clientes.
Para demonstrar a abordagem de DTO, atualize a classe TodoItem
para incluir um campo secreto:
namespace TodoApi.Models;
public class TodoItem
{
public long Id { get; set; }
public string? Name { get; set; }
public bool IsComplete { get; set; }
public string? Secret { get; set; }
}
O campo secreto precisa ser ocultado neste aplicativo, mas um aplicativo administrativo poderia optar por mostrá-lo.
Verifique se você pode postar e obter o campo secreto.
Crie um modelo de DTO em um arquivo Models/TodoItemsDTO.cs:
namespace TodoApi.Models;
public class TodoItemDTO
{
public long Id { get; set; }
public string? Name { get; set; }
public bool IsComplete { get; set; }
}
Atualize o TodoItemsController
para usar TodoItemDTO
:
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using TodoApi.Models;
namespace TodoApi.Controllers;
[Route("api/[controller]")]
[ApiController]
public class TodoItemsController : ControllerBase
{
private readonly TodoContext _context;
public TodoItemsController(TodoContext context)
{
_context = context;
}
// GET: api/TodoItems
[HttpGet]
public async Task<ActionResult<IEnumerable<TodoItemDTO>>> GetTodoItems()
{
return await _context.TodoItems
.Select(x => ItemToDTO(x))
.ToListAsync();
}
// GET: api/TodoItems/5
// <snippet_GetByID>
[HttpGet("{id}")]
public async Task<ActionResult<TodoItemDTO>> GetTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
return ItemToDTO(todoItem);
}
// </snippet_GetByID>
// PUT: api/TodoItems/5
// To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
// <snippet_Update>
[HttpPut("{id}")]
public async Task<IActionResult> PutTodoItem(long id, TodoItemDTO todoDTO)
{
if (id != todoDTO.Id)
{
return BadRequest();
}
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
todoItem.Name = todoDTO.Name;
todoItem.IsComplete = todoDTO.IsComplete;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException) when (!TodoItemExists(id))
{
return NotFound();
}
return NoContent();
}
// </snippet_Update>
// POST: api/TodoItems
// To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
// <snippet_Create>
[HttpPost]
public async Task<ActionResult<TodoItemDTO>> PostTodoItem(TodoItemDTO todoDTO)
{
var todoItem = new TodoItem
{
IsComplete = todoDTO.IsComplete,
Name = todoDTO.Name
};
_context.TodoItems.Add(todoItem);
await _context.SaveChangesAsync();
return CreatedAtAction(
nameof(GetTodoItem),
new { id = todoItem.Id },
ItemToDTO(todoItem));
}
// </snippet_Create>
// DELETE: api/TodoItems/5
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
_context.TodoItems.Remove(todoItem);
await _context.SaveChangesAsync();
return NoContent();
}
private bool TodoItemExists(long id)
{
return _context.TodoItems.Any(e => e.Id == id);
}
private static TodoItemDTO ItemToDTO(TodoItem todoItem) =>
new TodoItemDTO
{
Id = todoItem.Id,
Name = todoItem.Name,
IsComplete = todoItem.IsComplete
};
}
Verifique se você não pode postar ou obter o campo secreto.
Chamar a API Web com o JavaScript
Confira Tutorial: Chamar uma API Web do ASP.NET Core com o JavaScript.
Série de vídeos da API Web
Confira Vídeo: Série para iniciantes sobre APIs Web.
Padrões de aplicativo Web corporativo
Para obter diretrizes sobre como criar um aplicativo ASP.NET Core confiável, seguro, com desempenho, testável e escalonável, consulte padrões de aplicativo Web Enterprise. Há um aplicativo Web de amostra completo disponível, com qualidade de produção e que implementa os padrões.
Adicionar suporte de autenticação a uma API Web
O ASP.NET Core Identity adiciona a funcionalidade de login da interface do usuário (UI) 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)
- Servidor IdentityDuende
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 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 no .NET 5 para o .NET 6.
Para obter mais informações, confira a documentação do Duende Identity Server (site da Duende Software).
Publicar no Azure
Para obter informações sobre como implantar no Azure, consulte Início Rápido: Implantar um aplicativo Web ASP.NET.
Recursos adicionais
Exibir ou baixar o código de exemplo para este tutorial. Consulte como baixar.
Para obter mais informações, consulte os seguintes recursos:
- Criar APIs Web com o ASP.NET Core
- Tutorial: Criar uma API mínima com o ASP.NET Core
- Usar os documentos OpenAPI gerados
- Documentação da API Web ASP.NET Core com o Swagger/OpenAPI
- Razor Páginas com o Entity Framework Core no ASP.NET Core (tutorial 1 de 8)
- Roteamento para ações do controlador no ASP.NET Core
- Tipos de retorno de ação do controlador na API Web do ASP.NET Core
- Implantar aplicativos ASP.NET Core no Serviço de Aplicativo do Azure
- Hospedar e implantar o ASP.NET Core
- Criar uma API Web com o ASP.NET Core
Este tutorial ensina os conceitos básicos da criação de uma API Web baseada em controlador que usa um banco de dados. Outra abordagem para criar APIs no ASP.NET Core é criar APIs mínimas. Para obter ajuda na escolha entre APIs mínimas e APIs baseadas em controlador, veja Visão geral de APIs. Para obter um tutorial sobre como criar uma API mínima, confira Tutorial: Criar uma API mínima com ASP.NET Core.
Visão geral
Este tutorial cria a seguinte API:
Interface de Programação de Aplicativos (API) | Descrição | Corpo da solicitação | Corpo da resposta |
---|---|---|---|
GET /api/todoitems |
Obter todos os itens de tarefas pendentes | Nenhum | Matriz de itens de tarefas pendentes |
GET /api/todoitems/{id} |
Obter um item por ID | Nenhum | Item de tarefas pendentes |
POST /api/todoitems |
Adicionar um novo item | Item de tarefas pendentes | Item de tarefas pendentes |
PUT /api/todoitems/{id} |
Atualizar um item existente | Item de tarefas pendentes | Nenhum |
DELETE /api/todoitems/{id} |
Excluir um item | Nenhum | Nenhum |
O diagrama a seguir mostra o design do aplicativo.
Pré-requisitos
Visual Studio 2022 com a carga de trabalho de desenvolvimento Web e do ASP.NET.
Criar um projeto Web
- No menu Arquivo, selecione Novo>Projeto.
- Insira API Web na caixa de pesquisa.
- Selecione o modelo API Web do ASP.NET Core e Avançar.
- Na caixa de diálogo Configurar o novo projeto, nomeie o projeto TodoApi e selecione Avançar.
- Na caixa de diálogo Informações adicionais:
- Confirme se o Framework é .NET 8.0 (suporte a longo prazo).
- Confirme se a caixa de seleção Usar controladores (desmarque para utilizar APIs mínimas) está marcada.
- Confirme se a caixa de seleção Habilitar suporte a OpenAPI está marcada.
- Selecione Criar.
Adicionar um pacote NuGet
Um pacote NuGet deve ser adicionado para suportar o banco de dados utilizado neste tutorial.
- No menu Ferramentas, selecione Gerenciador de Pacotes do NuGet > Gerenciar Pacotes do NuGet para a Solução.
- Selecione a guia Navegar.
- Na caixa de pesquisa, insira Microsoft.EntityFrameworkCore.InMemory e selecione
Microsoft.EntityFrameworkCore.InMemory
. - Marque a caixa de seleção Projeto no painel direito e selecione Instalar.
Observação
Para obter diretrizes sobre como adicionar pacotes a aplicativos .NET, consulte os artigos em Instalar e gerenciar pacotes no Fluxo de trabalho de consumo de pacotes (documentação do NuGet). Confirme as versões corretas de pacote em NuGet.org.
Testar o projeto
O modelo de projeto cria uma API WeatherForecast
com suporte a Swagger.
Pressione Ctrl + F5 para execução sem o depurador.
O Visual Studio exibe a seguinte caixa de diálogo quando um projeto ainda não está configurado para usar o SSL:
Selecione Sim se você confia no certificado SSL do IIS Express.
A seguinte caixa de diálogo é exibida:
Selecione Sim se você concordar com confiar no certificado de desenvolvimento.
Para obter informações sobre como confiar no navegador Firefox, confira Erro de certificado Firefox SEC_ERROR_INADEQUATE_KEY_USAGE.
O Visual Studio inicia o navegador padrão e navega até https://localhost:<port>/swagger/index.html
, onde <port>
é um número de porta escolhido aleatoriamente na criação do projeto.
A página /swagger/index.html
do Swagger é exibida. Selecione Get>Try it out>Execute. A página exibe:
- O comando Curl para testar a API WeatherForecast.
- A URL para testar a API WeatherForecast.
- O código, o corpo e os cabeçalhos de resposta.
- Uma caixa de listagem suspensa com tipos de mídia e o valor e o esquema de exemplo.
Se a página do Swagger não aparecer, confira este problema do GitHub.
O Swagger é usado para gerar documentação útil e páginas de ajuda para APIs Web. Este tutorial utiliza o Swagger para testar o aplicativo. Para obter mais informações sobre o Swagger, confira a documentação da API Web do ASP.NET Core com Swagger/OpenAPI.
Copie e cole a URL de Solicitação no navegador: https://localhost:<port>/weatherforecast
É retornado JSON semelhante ao seguinte exemplo:
[
{
"date": "2019-07-16T19:04:05.7257911-06:00",
"temperatureC": 52,
"temperatureF": 125,
"summary": "Mild"
},
{
"date": "2019-07-17T19:04:05.7258461-06:00",
"temperatureC": 36,
"temperatureF": 96,
"summary": "Warm"
},
{
"date": "2019-07-18T19:04:05.7258467-06:00",
"temperatureC": 39,
"temperatureF": 102,
"summary": "Cool"
},
{
"date": "2019-07-19T19:04:05.7258471-06:00",
"temperatureC": 10,
"temperatureF": 49,
"summary": "Bracing"
},
{
"date": "2019-07-20T19:04:05.7258474-06:00",
"temperatureC": -1,
"temperatureF": 31,
"summary": "Chilly"
}
]
Adicionar uma classe de modelo
Um modelo é um conjunto de classes que representam os dados gerenciados pelo aplicativo. O modelo para este aplicativo é a classe TodoItem
.
- No Gerenciador de Soluções, clique com o botão direito do mouse no nome do projeto. Selecione Adicionar>nova pasta. Nomeie a pasta
Models
. - Clique com o botão direito do mouse na pasta
Models
e selecione Adicionar>Classe. Dê à classe o nome TodoItem e selecione Adicionar. - Substitua o código do modelo pelo seguinte:
namespace TodoApi.Models;
public class TodoItem
{
public long Id { get; set; }
public string? Name { get; set; }
public bool IsComplete { get; set; }
}
A propriedade Id
funciona como a chave exclusiva em um banco de dados relacional.
As classes de modelo podem ser colocadas em qualquer lugar no projeto, mas a pasta Models
é usada por convenção.
Adicionar um contexto de banco de dados
O contexto de banco de dados é a classe principal que coordena a funcionalidade do Entity Framework para um modelo de dados. Essa classe é criada derivando-a da classe Microsoft.EntityFrameworkCore.DbContext.
- Clique com o botão direito do mouse na pasta
Models
e selecione Adicionar>Classe. Nomeie a classe como TodoContext e clique em Adicionar.
Insira o seguinte código:
using Microsoft.EntityFrameworkCore; namespace TodoApi.Models; public class TodoContext : DbContext { public TodoContext(DbContextOptions<TodoContext> options) : base(options) { } public DbSet<TodoItem> TodoItems { get; set; } = null!; }
Registrar o contexto de banco de dados
No ASP.NET Core, serviços como o contexto do banco de dados precisam ser registrados no contêiner de injeção de dependência (DI). O contêiner fornece o serviço aos controladores.
Atualize Program.cs
com o seguinte código realçado:
using Microsoft.EntityFrameworkCore;
using TodoApi.Models;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddDbContext<TodoContext>(opt =>
opt.UseInMemoryDatabase("TodoList"));
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
O código anterior:
- Adiciona diretivas
using
. - Adiciona o contexto de banco de dados ao contêiner de DI.
- Especifica que o contexto de banco de dados usará um banco de dados em memória.
Faça scaffold de um controlador
Clique com o botão direito do mouse na pasta
Controllers
.Selecione Adicionar>New Scaffolded Item.
Selecione Controlador de API com ações, usando o Entity Framework e, em seguida, selecione Adicionar.
Na caixa de diálogo Adicionar Controlador de API com ações, usando o Entity Framework:
- Selecione TodoItem (TodoApi.Models) na classe Modelo.
- Selecione TodoContext (TodoApi.Models) na classe Contexto de Dados.
- Selecione Adicionar.
Se a operação de scaffolding falhar, selecione Adicionar para tentar estruturar uma segunda vez.
O código gerado:
- Marca a classe com o atributo
[ApiController]
. Esse atributo indica se o controlador responde às solicitações da API Web. Para obter informações sobre comportamentos específicos habilitados pelo atributo, confira Criar APIs Web com o ASP.NET Core. - Usa a DI para injetar o contexto de banco de dados (
TodoContext
) no controlador. O contexto de banco de dados é usado em cada um dos métodos CRUD no controlador.
Os modelos do ASP.NET Core para:
- Os controladores com exibições incluem
[action]
no modelo de rota. - Os controladores de API não incluem
[action]
no modelo de rota.
Quando o token [action]
não estiver no modelo de rota, o nome da ação (nome do método) não está incluído no ponto de extremidade. Ou seja, o nome do método associado da ação não é usado na rota correspondente.
Atualize o método PostTodoItem create
Atualize a instrução return no PostTodoItem
para usar o operador nameof:
[HttpPost]
public async Task<ActionResult<TodoItem>> PostTodoItem(TodoItem todoItem)
{
_context.TodoItems.Add(todoItem);
await _context.SaveChangesAsync();
// return CreatedAtAction("GetTodoItem", new { id = todoItem.Id }, todoItem);
return CreatedAtAction(nameof(GetTodoItem), new { id = todoItem.Id }, todoItem);
}
O código anterior é um método HTTP POST
, conforme indicado pelo atributo [HttpPost]
. O método obtém o valor do TodoItem
no corpo da solicitação HTTP.
Para obter mais informações, confira Roteamento de atributo com atributos Http[Verb].
O método CreatedAtAction:
- Retorna um código de status HTTP 201 em caso de êxito.
HTTP 201
é a resposta padrão para um métodoHTTP POST
que cria um recurso no servidor. - Adiciona um cabeçalho de Local à resposta. O cabeçalho
Location
especifica o URI do item de tarefas pendentes recém-criado. Para obter mais informações, confira 10.2.2 201 Criado. - Faz referência à ação
GetTodoItem
para criar o URI deLocation
do cabeçalho. A palavra-chavenameof
do C# é usada para evitar o hard-coding do nome da ação, na chamadaCreatedAtAction
.
Testar PostTodoItem
Pressione CTRL+F5 para executar o aplicativo.
Na janela do navegador Swagger, selecione POST /api/TodoItems e selecione Experimente.
Na janela de entrada Corpo da solicitação, atualize o JSON. Por exemplo,
{ "name": "walk dog", "isComplete": true }
Selecione Executar
Testar o URI do cabeçalho de local
No POST anterior, a interface do usuário do Swagger mostra o cabeçalho de local em cabeçalhos de resposta. Por exemplo, location: https://localhost:7260/api/TodoItems/1
. O cabeçalho de local mostra o URI para o recurso criado.
Para testar o cabeçalho de localização:
Na janela do navegador Swagger, selecione GET /api/TodoItems/{id} e selecione Experimente.
Insira
1
na caixa de entradaid
e selecione Executar.
Examine os métodos GET
Foram implementados dois endpoints GET:
GET /api/todoitems
GET /api/todoitems/{id}
A seção anterior mostrou um exemplo da rota /api/todoitems/{id}
.
Siga as instruções POST para adicionar outro item todo e teste a rota /api/todoitems
usando o Swagger.
Este aplicativo usa um banco de dados em memória. Se o aplicativo for interrompido e iniciado, a solicitação GET anterior não retornará nenhum dado. Se nenhum dado for retornado, envie dados usando POST para o aplicativo.
Roteamento e caminhos de URL
O atributo [HttpGet]
indica um método que responde a uma solicitação HTTP GET
. O caminho da URL de cada método é construído da seguinte maneira:
Comece com a cadeia de caracteres de modelo no atributo
Route
do controlador:[Route("api/[controller]")] [ApiController] public class TodoItemsController : ControllerBase
Substitua
[controller]
pelo nome do controlador, que é o nome de classe do controlador menos o sufixo "Controlador" por convenção. Para esta amostra, o nome da classe do controlador é TodoItemsController. Portanto, o nome do controlador é "TodoItems". O roteamento do ASP.NET Core não diferencia maiúsculas de minúsculas.Se o atributo
[HttpGet]
tiver um modelo de rota (por exemplo,[HttpGet("products")]
), acrescente isso ao caminho. Esta amostra não usa um modelo. Para obter mais informações, confira Roteamento de atributo com atributos Http[Verb].
No método GetTodoItem
a seguir, "{id}"
é uma variável de espaço reservado para o identificador exclusivo do item pendente. Quando GetTodoItem
é invocado, o valor de "{id}"
na URL é fornecido para o método no parâmetro id
.
[HttpGet("{id}")]
public async Task<ActionResult<TodoItem>> GetTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
return todoItem;
}
Valores retornados
O tipo de retorno dos métodos GetTodoItems
e GetTodoItem
é o tipo <ActionResult>T. O ASP.NET Core serializa automaticamente o objeto em JSON e grava o JSON no corpo da mensagem de resposta. O código de resposta para esse tipo de retorno é 200 OK, supondo que não haja nenhuma exceção sem tratamento. As exceções sem tratamento são convertidas em erros 5xx.
Os tipos de retorno ActionResult
podem representar uma ampla variedade de códigos de status HTTP. Por exemplo, GetTodoItem
pode retornar dois valores de status diferentes:
- Se nenhum item corresponder às ID solicitadas, o método retornará um código de erro status 404NotFound.
- Caso contrário, o método retornará 200 com um corpo de resposta JSON. O retorno de
item
resulta em uma respostaHTTP 200
.
O método PutTodoItem
Examine o método PutTodoItem
:
[HttpPut("{id}")]
public async Task<IActionResult> PutTodoItem(long id, TodoItem todoItem)
{
if (id != todoItem.Id)
{
return BadRequest();
}
_context.Entry(todoItem).State = EntityState.Modified;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!TodoItemExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return NoContent();
}
PutTodoItem
é semelhante a PostTodoItem
, exceto pelo uso de HTTP PUT
. A resposta é 204 (Sem conteúdo). De acordo com a especificação de HTTP, uma solicitação PUT
exige que o cliente envie a entidade inteira atualizada, não apenas as alterações. Para dar suporte a atualizações parciais, use HTTP PATCH.
Testar o método PutTodoItem
Este exemplo usa um banco de dados em memória que precisará ser iniciado sempre que o aplicativo for iniciado. Deverá haver um item no banco de dados antes de você fazer uma chamada PUT. Chame GET para garantir a existência de um item no banco de dados antes de fazer uma chamada PUT.
Usando a interface do usuário do Swagger, use o botão PUT para atualizar o TodoItem
que tem ID = 1 e definir seu nome como "feed fish"
. Observe que a resposta é HTTP 204 No Content
.
O método DeleteTodoItem
Examine o método DeleteTodoItem
:
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
_context.TodoItems.Remove(todoItem);
await _context.SaveChangesAsync();
return NoContent();
}
Testar o método DeleteTodoItem
Use a interface do usuário do Swagger para excluir o TodoItem
que tem ID = 1. Observe que a resposta é HTTP 204 No Content
.
Teste com outras ferramentas
Existem muitas outras ferramentas que podem ser utilizadas para testar APIs Web, por exemplo:
- Explorador de Endpoints do Visual Studio e arquivos .http
- http-repl
-
curl. O Swagger utiliza
curl
e mostra os comandoscurl
que envia. - Violinista
Para obter mais informações, consulte:
Impedir o excesso de postagem
Atualmente, o aplicativo de exemplo expõe todo o objeto TodoItem
. Os aplicativos de produção normalmente limitam os dados de entrada e saída usando um subconjunto do modelo. Há várias razões por trás disso, e a segurança é uma das principais. O subconjunto de um modelo geralmente é chamado de DTO (Objeto de Transferência de Dados), modelo de entrada ou modelo de exibição. O DTO é usado neste tutorial.
Um DTO pode ser usado para:
- Impedir o excesso de postagem.
- Ocultar propriedades que os clientes não devem visualizar.
- Omitir algumas propriedades para reduzir o tamanho da carga.
- Nivelar gráficos de objetos que contenham objetos aninhados. Os grafos de objeto nivelados podem ser mais convenientes para os clientes.
Para demonstrar a abordagem de DTO, atualize a classe TodoItem
para incluir um campo secreto:
namespace TodoApi.Models
{
public class TodoItem
{
public long Id { get; set; }
public string? Name { get; set; }
public bool IsComplete { get; set; }
public string? Secret { get; set; }
}
}
O campo secreto precisa ser ocultado neste aplicativo, mas um aplicativo administrativo poderia optar por mostrá-lo.
Verifique se você pode postar e obter o campo secreto.
Crie um modelo de DTO:
namespace TodoApi.Models;
public class TodoItemDTO
{
public long Id { get; set; }
public string? Name { get; set; }
public bool IsComplete { get; set; }
}
Atualize o TodoItemsController
para usar TodoItemDTO
:
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using TodoApi.Models;
namespace TodoApi.Controllers;
[Route("api/[controller]")]
[ApiController]
public class TodoItemsController : ControllerBase
{
private readonly TodoContext _context;
public TodoItemsController(TodoContext context)
{
_context = context;
}
// GET: api/TodoItems
[HttpGet]
public async Task<ActionResult<IEnumerable<TodoItemDTO>>> GetTodoItems()
{
return await _context.TodoItems
.Select(x => ItemToDTO(x))
.ToListAsync();
}
// GET: api/TodoItems/5
// <snippet_GetByID>
[HttpGet("{id}")]
public async Task<ActionResult<TodoItemDTO>> GetTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
return ItemToDTO(todoItem);
}
// </snippet_GetByID>
// PUT: api/TodoItems/5
// To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
// <snippet_Update>
[HttpPut("{id}")]
public async Task<IActionResult> PutTodoItem(long id, TodoItemDTO todoDTO)
{
if (id != todoDTO.Id)
{
return BadRequest();
}
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
todoItem.Name = todoDTO.Name;
todoItem.IsComplete = todoDTO.IsComplete;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException) when (!TodoItemExists(id))
{
return NotFound();
}
return NoContent();
}
// </snippet_Update>
// POST: api/TodoItems
// To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
// <snippet_Create>
[HttpPost]
public async Task<ActionResult<TodoItemDTO>> PostTodoItem(TodoItemDTO todoDTO)
{
var todoItem = new TodoItem
{
IsComplete = todoDTO.IsComplete,
Name = todoDTO.Name
};
_context.TodoItems.Add(todoItem);
await _context.SaveChangesAsync();
return CreatedAtAction(
nameof(GetTodoItem),
new { id = todoItem.Id },
ItemToDTO(todoItem));
}
// </snippet_Create>
// DELETE: api/TodoItems/5
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
_context.TodoItems.Remove(todoItem);
await _context.SaveChangesAsync();
return NoContent();
}
private bool TodoItemExists(long id)
{
return _context.TodoItems.Any(e => e.Id == id);
}
private static TodoItemDTO ItemToDTO(TodoItem todoItem) =>
new TodoItemDTO
{
Id = todoItem.Id,
Name = todoItem.Name,
IsComplete = todoItem.IsComplete
};
}
Verifique se você não pode postar ou obter o campo secreto.
Chamar a API Web com o JavaScript
Confira Tutorial: Chamar uma API Web do ASP.NET Core com o JavaScript.
Série de vídeos da API Web
Confira Vídeo: Série para iniciantes sobre APIs Web.
Padrões de aplicativo Web corporativo
Para obter diretrizes sobre como criar um aplicativo ASP.NET Core confiável, seguro, com desempenho, testável e escalonável, consulte padrões de aplicativo Web Enterprise. Há um aplicativo Web de amostra completo disponível, com qualidade de produção e que implementa os padrões.
Adicionar suporte de autenticação a uma API Web
O ASP.NET Core Identity adiciona a funcionalidade de login da interface do usuário (UI) 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)
- Servidor IdentityDuende
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 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 no .NET 5 para o .NET 6.
Para obter mais informações, confira a documentação do Duende Identity Server (site da Duende Software).
Publicar no Azure
Para obter informações sobre como implantar no Azure, consulte Início Rápido: Implantar um aplicativo Web ASP.NET.
Recursos adicionais
Exibir ou baixar o código de exemplo para este tutorial. Consulte como baixar.
Para obter mais informações, consulte os seguintes recursos:
- Criar APIs Web com o ASP.NET Core
- Tutorial: Criar uma API mínima com o ASP.NET Core
- Documentação da API Web ASP.NET Core com o Swagger/OpenAPI
- Razor Páginas com o Entity Framework Core no ASP.NET Core (tutorial 1 de 8)
- Roteamento para ações do controlador no ASP.NET Core
- Tipos de retorno de ação do controlador na API Web do ASP.NET Core
- Implantar aplicativos ASP.NET Core no Serviço de Aplicativo do Azure
- Hospedar e implantar o ASP.NET Core
- Criar uma API Web com o ASP.NET Core
Este tutorial ensina os conceitos básicos da criação de uma API Web baseada em controlador que usa um banco de dados. Outra abordagem para criar APIs no ASP.NET Core é criar APIs mínimas. Para obter ajuda na escolha entre APIs mínimas e APIs baseadas em controlador, veja Visão geral de APIs. Para obter um tutorial sobre como criar uma API mínima, confira Tutorial: Criar uma API mínima com ASP.NET Core.
Visão geral
Este tutorial cria a seguinte API:
Interface de Programação de Aplicativos (API) | Descrição | Corpo da solicitação | Corpo da resposta |
---|---|---|---|
GET /api/todoitems |
Obter todos os itens de tarefas pendentes | Nenhum | Matriz de itens de tarefas pendentes |
GET /api/todoitems/{id} |
Obter um item por ID | Nenhum | Item de tarefas pendentes |
POST /api/todoitems |
Adicionar um novo item | Item de tarefas pendentes | Item de tarefas pendentes |
PUT /api/todoitems/{id} |
Atualizar um item existente | Item de tarefas pendentes | Nenhum |
DELETE /api/todoitems/{id} |
Excluir um item | Nenhum | Nenhum |
O diagrama a seguir mostra o design do aplicativo.
Pré-requisitos
Visual Studio 2022 com a carga de trabalho de desenvolvimento Web e do ASP.NET.
Criar um projeto Web
- No menu Arquivo, selecione Novo>Projeto.
- Insira API Web na caixa de pesquisa.
- Selecione o modelo API Web do ASP.NET Core e Avançar.
- Na caixa de diálogo Configurar o novo projeto, nomeie o projeto TodoApi e selecione Avançar.
- Na caixa de diálogo Informações adicionais:
- Confirme se o Framework é .NET 8.0 (suporte a longo prazo).
- Confirme se a caixa de seleção Usar controladores (desmarque para utilizar APIs mínimas) está marcada.
- Confirme se a caixa de seleção Habilitar suporte a OpenAPI está marcada.
- Selecione Criar.
Adicionar um pacote NuGet
Um pacote NuGet deve ser adicionado para suportar o banco de dados utilizado neste tutorial.
- No menu Ferramentas, selecione Gerenciador de Pacotes do NuGet > Gerenciar Pacotes do NuGet para a Solução.
- Selecione a guia Navegar.
- Na caixa de pesquisa, insira Microsoft.EntityFrameworkCore.InMemory e selecione
Microsoft.EntityFrameworkCore.InMemory
. - Marque a caixa de seleção Projeto no painel direito e selecione Instalar.
Observação
Para obter diretrizes sobre como adicionar pacotes a aplicativos .NET, consulte os artigos em Instalar e gerenciar pacotes no Fluxo de trabalho de consumo de pacotes (documentação do NuGet). Confirme as versões corretas de pacote em NuGet.org.
Testar o projeto
O modelo de projeto cria uma API WeatherForecast
com suporte a Swagger.
Pressione Ctrl + F5 para execução sem o depurador.
O Visual Studio exibe a seguinte caixa de diálogo quando um projeto ainda não está configurado para usar o SSL:
Selecione Sim se você confia no certificado SSL do IIS Express.
A seguinte caixa de diálogo é exibida:
Selecione Sim se você concordar com confiar no certificado de desenvolvimento.
Para obter informações sobre como confiar no navegador Firefox, confira Erro de certificado Firefox SEC_ERROR_INADEQUATE_KEY_USAGE.
O Visual Studio inicia o navegador padrão e navega até https://localhost:<port>/swagger/index.html
, onde <port>
é um número de porta escolhido aleatoriamente na criação do projeto.
A página /swagger/index.html
do Swagger é exibida. Selecione Get>Try it out>Execute. A página exibe:
- O comando Curl para testar a API WeatherForecast.
- A URL para testar a API WeatherForecast.
- O código, o corpo e os cabeçalhos de resposta.
- Uma caixa de listagem suspensa com tipos de mídia e o valor e o esquema de exemplo.
Se a página do Swagger não aparecer, confira este problema do GitHub.
O Swagger é usado para gerar documentação útil e páginas de ajuda para APIs Web. Este tutorial utiliza o Swagger para testar o aplicativo. Para obter mais informações sobre o Swagger, confira a documentação da API Web do ASP.NET Core com Swagger/OpenAPI.
Copie e cole a URL de Solicitação no navegador: https://localhost:<port>/weatherforecast
É retornado JSON semelhante ao seguinte exemplo:
[
{
"date": "2019-07-16T19:04:05.7257911-06:00",
"temperatureC": 52,
"temperatureF": 125,
"summary": "Mild"
},
{
"date": "2019-07-17T19:04:05.7258461-06:00",
"temperatureC": 36,
"temperatureF": 96,
"summary": "Warm"
},
{
"date": "2019-07-18T19:04:05.7258467-06:00",
"temperatureC": 39,
"temperatureF": 102,
"summary": "Cool"
},
{
"date": "2019-07-19T19:04:05.7258471-06:00",
"temperatureC": 10,
"temperatureF": 49,
"summary": "Bracing"
},
{
"date": "2019-07-20T19:04:05.7258474-06:00",
"temperatureC": -1,
"temperatureF": 31,
"summary": "Chilly"
}
]
Adicionar uma classe de modelo
Um modelo é um conjunto de classes que representam os dados gerenciados pelo aplicativo. O modelo para este aplicativo é a classe TodoItem
.
- No Gerenciador de Soluções, clique com o botão direito do mouse no nome do projeto. Selecione Adicionar>nova pasta. Nomeie a pasta
Models
. - Clique com o botão direito do mouse na pasta
Models
e selecione Adicionar>Classe. Dê à classe o nome TodoItem e selecione Adicionar. - Substitua o código do modelo pelo seguinte:
namespace TodoApi.Models;
public class TodoItem
{
public long Id { get; set; }
public string? Name { get; set; }
public bool IsComplete { get; set; }
}
A propriedade Id
funciona como a chave exclusiva em um banco de dados relacional.
As classes de modelo podem ser colocadas em qualquer lugar no projeto, mas a pasta Models
é usada por convenção.
Adicionar um contexto de banco de dados
O contexto de banco de dados é a classe principal que coordena a funcionalidade do Entity Framework para um modelo de dados. Essa classe é criada derivando-a da classe Microsoft.EntityFrameworkCore.DbContext.
- Clique com o botão direito do mouse na pasta
Models
e selecione Adicionar>Classe. Nomeie a classe como TodoContext e clique em Adicionar.
Insira o seguinte código:
using Microsoft.EntityFrameworkCore; namespace TodoApi.Models; public class TodoContext : DbContext { public TodoContext(DbContextOptions<TodoContext> options) : base(options) { } public DbSet<TodoItem> TodoItems { get; set; } = null!; }
Registrar o contexto de banco de dados
No ASP.NET Core, serviços como o contexto do banco de dados precisam ser registrados no contêiner de injeção de dependência (DI). O contêiner fornece o serviço aos controladores.
Atualize Program.cs
com o seguinte código realçado:
using Microsoft.EntityFrameworkCore;
using TodoApi.Models;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddDbContext<TodoContext>(opt =>
opt.UseInMemoryDatabase("TodoList"));
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
O código anterior:
- Adiciona diretivas
using
. - Adiciona o contexto de banco de dados ao contêiner de DI.
- Especifica que o contexto de banco de dados usará um banco de dados em memória.
Faça scaffold de um controlador
Clique com o botão direito do mouse na pasta
Controllers
.Selecione Adicionar>New Scaffolded Item.
Selecione Controlador de API com ações, usando o Entity Framework e, em seguida, selecione Adicionar.
Na caixa de diálogo Adicionar Controlador de API com ações, usando o Entity Framework:
- Selecione TodoItem (TodoApi.Models) na classe Modelo.
- Selecione TodoContext (TodoApi.Models) na classe Contexto de Dados.
- Selecione Adicionar.
Se a operação de scaffolding falhar, selecione Adicionar para tentar estruturar uma segunda vez.
O código gerado:
- Marca a classe com o atributo
[ApiController]
. Esse atributo indica se o controlador responde às solicitações da API Web. Para obter informações sobre comportamentos específicos habilitados pelo atributo, confira Criar APIs Web com o ASP.NET Core. - Usa a DI para injetar o contexto de banco de dados (
TodoContext
) no controlador. O contexto de banco de dados é usado em cada um dos métodos CRUD no controlador.
Os modelos do ASP.NET Core para:
- Os controladores com exibições incluem
[action]
no modelo de rota. - Os controladores de API não incluem
[action]
no modelo de rota.
Quando o token [action]
não estiver no modelo de rota, o nome da ação (nome do método) não está incluído no ponto de extremidade. Ou seja, o nome do método associado da ação não é usado na rota correspondente.
Atualize o método PostTodoItem create
Atualize a instrução return no PostTodoItem
para usar o operador nameof:
[HttpPost]
public async Task<ActionResult<TodoItem>> PostTodoItem(TodoItem todoItem)
{
_context.TodoItems.Add(todoItem);
await _context.SaveChangesAsync();
// return CreatedAtAction("GetTodoItem", new { id = todoItem.Id }, todoItem);
return CreatedAtAction(nameof(GetTodoItem), new { id = todoItem.Id }, todoItem);
}
O código anterior é um método HTTP POST
, conforme indicado pelo atributo [HttpPost]
. O método obtém o valor do TodoItem
no corpo da solicitação HTTP.
Para obter mais informações, confira Roteamento de atributo com atributos Http[Verb].
O método CreatedAtAction:
- Retorna um código de status HTTP 201 em caso de êxito.
HTTP 201
é a resposta padrão para um métodoHTTP POST
que cria um recurso no servidor. - Adiciona um cabeçalho de Local à resposta. O cabeçalho
Location
especifica o URI do item de tarefas pendentes recém-criado. Para obter mais informações, confira 10.2.2 201 Criado. - Faz referência à ação
GetTodoItem
para criar o URI deLocation
do cabeçalho. A palavra-chavenameof
do C# é usada para evitar o hard-coding do nome da ação, na chamadaCreatedAtAction
.
Testar PostTodoItem
Pressione CTRL+F5 para executar o aplicativo.
Na janela do navegador Swagger, selecione POST /api/TodoItems e selecione Experimente.
Na janela de entrada Corpo da solicitação, atualize o JSON. Por exemplo,
{ "name": "walk dog", "isComplete": true }
Selecione Executar
Testar o URI do cabeçalho de local
No POST anterior, a interface do usuário do Swagger mostra o cabeçalho de local em cabeçalhos de resposta. Por exemplo, location: https://localhost:7260/api/TodoItems/1
. O cabeçalho de local mostra o URI para o recurso criado.
Para testar o cabeçalho de localização:
Na janela do navegador Swagger, selecione GET /api/TodoItems/{id} e selecione Experimente.
Insira
1
na caixa de entradaid
e selecione Executar.
Examine os métodos GET
Foram implementados dois endpoints GET:
GET /api/todoitems
GET /api/todoitems/{id}
A seção anterior mostrou um exemplo da rota /api/todoitems/{id}
.
Siga as instruções POST para adicionar outro item todo e teste a rota /api/todoitems
usando o Swagger.
Este aplicativo usa um banco de dados em memória. Se o aplicativo for interrompido e iniciado, a solicitação GET anterior não retornará nenhum dado. Se nenhum dado for retornado, envie dados usando POST para o aplicativo.
Roteamento e caminhos de URL
O atributo [HttpGet]
indica um método que responde a uma solicitação HTTP GET
. O caminho da URL de cada método é construído da seguinte maneira:
Comece com a cadeia de caracteres de modelo no atributo
Route
do controlador:[Route("api/[controller]")] [ApiController] public class TodoItemsController : ControllerBase
Substitua
[controller]
pelo nome do controlador, que é o nome de classe do controlador menos o sufixo "Controlador" por convenção. Para esta amostra, o nome da classe do controlador é TodoItemsController. Portanto, o nome do controlador é "TodoItems". O roteamento do ASP.NET Core não diferencia maiúsculas de minúsculas.Se o atributo
[HttpGet]
tiver um modelo de rota (por exemplo,[HttpGet("products")]
), acrescente isso ao caminho. Esta amostra não usa um modelo. Para obter mais informações, confira Roteamento de atributo com atributos Http[Verb].
No método GetTodoItem
a seguir, "{id}"
é uma variável de espaço reservado para o identificador exclusivo do item pendente. Quando GetTodoItem
é invocado, o valor de "{id}"
na URL é fornecido para o método no parâmetro id
.
[HttpGet("{id}")]
public async Task<ActionResult<TodoItem>> GetTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
return todoItem;
}
Valores retornados
O tipo de retorno dos métodos GetTodoItems
e GetTodoItem
é o tipo <ActionResult>T. O ASP.NET Core serializa automaticamente o objeto em JSON e grava o JSON no corpo da mensagem de resposta. O código de resposta para esse tipo de retorno é 200 OK, supondo que não haja nenhuma exceção sem tratamento. As exceções sem tratamento são convertidas em erros 5xx.
Os tipos de retorno ActionResult
podem representar uma ampla variedade de códigos de status HTTP. Por exemplo, GetTodoItem
pode retornar dois valores de status diferentes:
- Se nenhum item corresponder às ID solicitadas, o método retornará um código de erro status 404NotFound.
- Caso contrário, o método retornará 200 com um corpo de resposta JSON. O retorno de
item
resulta em uma respostaHTTP 200
.
O método PutTodoItem
Examine o método PutTodoItem
:
[HttpPut("{id}")]
public async Task<IActionResult> PutTodoItem(long id, TodoItem todoItem)
{
if (id != todoItem.Id)
{
return BadRequest();
}
_context.Entry(todoItem).State = EntityState.Modified;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!TodoItemExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return NoContent();
}
PutTodoItem
é semelhante a PostTodoItem
, exceto pelo uso de HTTP PUT
. A resposta é 204 (Sem conteúdo). De acordo com a especificação de HTTP, uma solicitação PUT
exige que o cliente envie a entidade inteira atualizada, não apenas as alterações. Para dar suporte a atualizações parciais, use HTTP PATCH.
Testar o método PutTodoItem
Este exemplo usa um banco de dados em memória que precisará ser iniciado sempre que o aplicativo for iniciado. Deverá haver um item no banco de dados antes de você fazer uma chamada PUT. Chame GET para garantir a existência de um item no banco de dados antes de fazer uma chamada PUT.
Usando a interface do usuário do Swagger, use o botão PUT para atualizar o TodoItem
que tem ID = 1 e definir seu nome como "feed fish"
. Observe que a resposta é HTTP 204 No Content
.
O método DeleteTodoItem
Examine o método DeleteTodoItem
:
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
_context.TodoItems.Remove(todoItem);
await _context.SaveChangesAsync();
return NoContent();
}
Testar o método DeleteTodoItem
Use a interface do usuário do Swagger para excluir o TodoItem
que tem ID = 1. Observe que a resposta é HTTP 204 No Content
.
Teste com outras ferramentas
Existem muitas outras ferramentas que podem ser utilizadas para testar APIs Web, por exemplo:
- Explorador de Endpoints do Visual Studio e arquivos .http
- http-repl
-
curl. O Swagger utiliza
curl
e mostra os comandoscurl
que envia. - Violinista
Para obter mais informações, consulte:
Impedir o excesso de postagem
Atualmente, o aplicativo de exemplo expõe todo o objeto TodoItem
. Os aplicativos de produção normalmente limitam os dados de entrada e saída usando um subconjunto do modelo. Há várias razões por trás disso, e a segurança é uma das principais. O subconjunto de um modelo geralmente é chamado de DTO (Objeto de Transferência de Dados), modelo de entrada ou modelo de exibição. O DTO é usado neste tutorial.
Um DTO pode ser usado para:
- Impedir o excesso de postagem.
- Ocultar propriedades que os clientes não devem visualizar.
- Omitir algumas propriedades para reduzir o tamanho da carga.
- Nivelar gráficos de objetos que contenham objetos aninhados. Os grafos de objeto nivelados podem ser mais convenientes para os clientes.
Para demonstrar a abordagem de DTO, atualize a classe TodoItem
para incluir um campo secreto:
namespace TodoApi.Models
{
public class TodoItem
{
public long Id { get; set; }
public string? Name { get; set; }
public bool IsComplete { get; set; }
public string? Secret { get; set; }
}
}
O campo secreto precisa ser ocultado neste aplicativo, mas um aplicativo administrativo poderia optar por mostrá-lo.
Verifique se você pode postar e obter o campo secreto.
Crie um modelo de DTO:
namespace TodoApi.Models;
public class TodoItemDTO
{
public long Id { get; set; }
public string? Name { get; set; }
public bool IsComplete { get; set; }
}
Atualize o TodoItemsController
para usar TodoItemDTO
:
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using TodoApi.Models;
namespace TodoApi.Controllers;
[Route("api/[controller]")]
[ApiController]
public class TodoItemsController : ControllerBase
{
private readonly TodoContext _context;
public TodoItemsController(TodoContext context)
{
_context = context;
}
// GET: api/TodoItems
[HttpGet]
public async Task<ActionResult<IEnumerable<TodoItemDTO>>> GetTodoItems()
{
return await _context.TodoItems
.Select(x => ItemToDTO(x))
.ToListAsync();
}
// GET: api/TodoItems/5
// <snippet_GetByID>
[HttpGet("{id}")]
public async Task<ActionResult<TodoItemDTO>> GetTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
return ItemToDTO(todoItem);
}
// </snippet_GetByID>
// PUT: api/TodoItems/5
// To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
// <snippet_Update>
[HttpPut("{id}")]
public async Task<IActionResult> PutTodoItem(long id, TodoItemDTO todoDTO)
{
if (id != todoDTO.Id)
{
return BadRequest();
}
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
todoItem.Name = todoDTO.Name;
todoItem.IsComplete = todoDTO.IsComplete;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException) when (!TodoItemExists(id))
{
return NotFound();
}
return NoContent();
}
// </snippet_Update>
// POST: api/TodoItems
// To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
// <snippet_Create>
[HttpPost]
public async Task<ActionResult<TodoItemDTO>> PostTodoItem(TodoItemDTO todoDTO)
{
var todoItem = new TodoItem
{
IsComplete = todoDTO.IsComplete,
Name = todoDTO.Name
};
_context.TodoItems.Add(todoItem);
await _context.SaveChangesAsync();
return CreatedAtAction(
nameof(GetTodoItem),
new { id = todoItem.Id },
ItemToDTO(todoItem));
}
// </snippet_Create>
// DELETE: api/TodoItems/5
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
_context.TodoItems.Remove(todoItem);
await _context.SaveChangesAsync();
return NoContent();
}
private bool TodoItemExists(long id)
{
return _context.TodoItems.Any(e => e.Id == id);
}
private static TodoItemDTO ItemToDTO(TodoItem todoItem) =>
new TodoItemDTO
{
Id = todoItem.Id,
Name = todoItem.Name,
IsComplete = todoItem.IsComplete
};
}
Verifique se você não pode postar ou obter o campo secreto.
Chamar a API Web com o JavaScript
Confira Tutorial: Chamar uma API Web do ASP.NET Core com o JavaScript.
Série de vídeos da API Web
Confira Vídeo: Série para iniciantes sobre APIs Web.
Padrões de aplicativo Web corporativo
Para obter diretrizes sobre como criar um aplicativo ASP.NET Core confiável, seguro, com desempenho, testável e escalonável, consulte padrões de aplicativo Web Enterprise. Há um aplicativo Web de amostra completo disponível, com qualidade de produção e que implementa os padrões.
Adicionar suporte de autenticação a uma API Web
O ASP.NET Core Identity adiciona a funcionalidade de login da interface do usuário (UI) 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)
- Servidor IdentityDuende
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 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 no .NET 5 para o .NET 6.
Para obter mais informações, confira a documentação do Duende Identity Server (site da Duende Software).
Publicar no Azure
Para obter informações sobre como implantar no Azure, consulte Início Rápido: Implantar um aplicativo Web ASP.NET.
Recursos adicionais
Exibir ou baixar o código de exemplo para este tutorial. Consulte como baixar.
Para obter mais informações, consulte os seguintes recursos:
- Criar APIs Web com o ASP.NET Core
- Tutorial: Criar uma API mínima com o ASP.NET Core
- Documentação da API Web ASP.NET Core com o Swagger/OpenAPI
- Razor Páginas com o Entity Framework Core no ASP.NET Core (tutorial 1 de 8)
- Roteamento para ações do controlador no ASP.NET Core
- Tipos de retorno de ação do controlador na API Web do ASP.NET Core
- Implantar aplicativos ASP.NET Core no Serviço de Aplicativo do Azure
- Hospedar e implantar o ASP.NET Core
- Criar uma API Web com o ASP.NET Core