Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
Note
Esta não é a versão mais recente deste artigo. Para a versão atual, consulte a versão .NET 10 deste artigo.
Warning
Esta versão do ASP.NET Core não é mais suportada. Para obter mais informações, consulte a Política de suporte do .NET e .NET Core. 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 da 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 com a escolha entre APIs mínimas e APIs baseadas em controlador, consulte Visão geral de APIs. Para obter um tutorial sobre como criar uma API mínima, consulte Tutorial: Criar uma API mínima com o ASP.NET Core.
Overview
Este tutorial cria a seguinte API:
| API | Description | Corpo de solicitação | Corpo da resposta |
|---|---|---|---|
GET /api/todoitems |
Consiga todos os itens to-do | None | Lista de tarefas a fazer |
GET /api/todoitems/{id} |
Obter um item pelo ID | None | Item de tarefa |
POST /api/todoitems |
Adicionar um novo item | Item de tarefa | Item de tarefa |
PUT /api/todoitems/{id} |
Atualizar um item existente | Item de tarefa | None |
DELETE /api/todoitems/{id} |
Excluir um item | None | None |
O diagrama a seguir mostra o design do aplicativo.
Prerequisites
Visual Studio 2022 com a carga de trabalho ASP.NET e desenvolvimento web.
Criar um projeto de API Web
- No menu Arquivo, selecione Novo>Projeto.
- Digite Web API na caixa de pesquisa.
- Selecione o modelo
ASP.NET Core Web API e selecione Next . - Na caixa de diálogo Configurar seu novo projeto, nomeie o projeto como TodoApi e selecione Avançar.
- No caixa de diálogo de Informações adicionais :
- Confirme se o Framework é .NET 9.0 (Standard Term Support).
- Confirme que a caixa de seleção Ativar suporte a OpenAPI está marcada.
- Confirme se a caixa de seleção Usar controladores (desmarque para usar APIs mínimas) está marcada.
- Selecione Criar.
Adicionar um pacote NuGet
Um pacote NuGet deve ser adicionado para dar suporte ao banco de dados usado neste tutorial.
- No menu Ferramentas, selecione Gerenciador de Pacotes NuGet > Gerenciar Pacotes NuGet para Solução.
- Selecione a guia Procurar.
- Digite Microsoft.EntityFrameworkCore.InMemory na caixa de pesquisa e selecione
Microsoft.EntityFrameworkCore.InMemory. - Marque a caixa de seleção Projeto no painel direito e selecione Instalar.
Note
Para obter orientação sobre como adicionar pacotes a aplicativos .NET, consulte os artigos na seção Instalar e gerenciar pacotes em Workflow de utilização de pacotes (documentação do NuGet). Confirme as versões corretas do pacote em NuGet.org.
Executar o projeto
O modelo de projeto cria uma WeatherForecast API com suporte para OpenAPI.
Pressione Ctrl+F5 para executar sem o depurador.
Visual Studio exibe a seguinte caixa de diálogo quando um projeto ainda não está configurado para usar SSL:
Selecione Sim se confiar no certificado SSL do IIS Express.
A seguinte caixa de diálogo é exibida:
Selecione Sim se concordar em confiar no certificado de desenvolvimento.
Para obter informações sobre como confiar no navegador Firefox, consulte o erro de certificado SEC_ERROR_INADEQUATE_KEY_USAGE do Firefox na secção .
O Visual Studio inicia uma janela de terminal e exibe a URL do aplicativo em execução. A API é hospedada em https://localhost:<port>, onde <port> é um número de porta escolhido aleatoriamente definido 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 URL HTTPS na saída para testar o aplicativo Web em um navegador. Não há nenhum endpoint no https://localhost:<port>, então o navegador retorna HTTP 404 Não Encontrado.
Anexe /weatherforecast ao URL para testar a API WeatherForecast.
O navegador exibe JSON semelhante ao exemplo a seguir:
[
{
"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 Endpoints Explorer e arquivos .http para testar a API.
Adicionar uma classe de modelo
Um modelo é um conjunto de classes que representam os dados que o aplicativo gerencia. O modelo para este aplicativo é a TodoItem classe.
- No Gerenciador de Soluções , clique com o botão direito do mouse no projeto. Selecione Adicionar>Nova Pasta. Dê um nome à pasta
Models. - Clique com o botão direito do mouse na
Modelspasta e selecione Adicionar>classe. Nomeie a classe 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 Id propriedade funciona como a chave exclusiva em um banco de dados relacional.
As classes de modelo podem ir para qualquer lugar no projeto, mas a Models pasta é usada por convenção.
Adicionar um contexto de banco de dados
O contexto do banco de dados é a classe principal que coordena a funcionalidade do Entity Framework para um modelo de dados. Essa classe é criada derivando da classe Microsoft.EntityFrameworkCore.DbContext.
Clique com o botão direito do mouse na
Modelspasta e selecione Adicionar>classe. Nomeie a classe 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 do banco de dados
No ASP.NET Core, serviços como o contexto de banco de dados devem ser registrados com o 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 destacado:
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:
- Acrescenta
usingdiretivas. - Adiciona o contexto do banco de dados ao contêiner DI.
- Especifica que o contexto do banco de dados usará um banco de dados na memória.
Andaime um controlador
Clique com o botão direito do rato 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 Model.
- Selecione TodoContext (TodoApi.Models) na classe de contexto Data.
- Selecione Adicionar.
Se a operação de andaime falhar, selecione Adicionar para tentar andaimes uma segunda vez.
Esta etapa adiciona os Microsoft.VisualStudio.Web.CodeGeneration.Design pacotes e Microsoft.EntityFrameworkCore.Tools NuGet ao projeto.
Estas embalagens são necessárias para andaimes.
O código gerado:
- Marca a classe com o
[ApiController]atributo. Esse atributo indica que o controlador responde a solicitações de API da Web. Para obter informações sobre comportamentos específicos habilitados pelo atributo, consulte Criar APIs da Web com ASP.NET Core. - Usa DI para injetar o contexto da base de dados (
TodoContext) no controlador. O contexto do banco de dados é usado em cada um dos métodos CRUD no controlador.
Os modelos ASP.NET Core para:
- Os controladores com views incluem
[action]no modelo de rota. - Os controladores de API não incluem
[action]no modelo de rota.
Quando o [action] token não está no modelo de rota, o nome da ação (nome do método) não é incluído no ponto de extremidade. Ou seja, o nome do método associado à ação não é usado na rota correspondente.
Atualizar o método de criação PostTodoItem
Atualize a instrução de retorno 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 HTTP POST método, conforme indicado pelo [HttpPost] atributo. O método obtém o valor do TodoItem do corpo da solicitação HTTP.
Para obter mais informações, consulte Roteamento de atributos com atributos Http[Verb].
O método CreatedAtAction:
- Retorna um código de status HTTP 201 se for bem-sucedido.
HTTP 201é a resposta padrão para umHTTP POSTmétodo que cria um novo recurso no servidor. - Adiciona um cabeçalho Location à resposta. O
Locationcabeçalho especifica o URI do item to-do recém-criado. Para obter mais informações, consulte 10.2.2 201 Criado. - Faz referência à ação
GetTodoItempara criar o URI do cabeçalhoLocation. A palavra-chave C#nameofé usada para evitar a codificação direta do nome da ação na chamadaCreatedAtAction.
Teste PostTodoItem
Selecione Ver>Outras Janelas>Explorador de Endpoints.
Clique com o botão direito em POST endpoint e selecione Gerar solicitação.
Um novo arquivo é criado na pasta do 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 três hashtags (
###) é um delimitador de solicitação: o que vem depois é para uma solicitação diferente.
O pedido POST espera um
TodoItem. Para definir o todo, substitua o//TodoItemcomentário pelo seguinte JSON:{ "name": "walk dog", "isComplete": true }O ficheiro TodoApi.http agora deve assemelhar-se ao exemplo abaixo, 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 que está acima da linha de solicitação
POST.
A solicitação POST é enviada para a aplicação e a resposta é exibida no painel de Resposta .
Testar o URI do cabeçalho de localização
Teste a aplicação chamando os endpoints GET de um navegador ou usando o Explorador de Endpoints. As etapas a seguir são para Endpoints Explorer.
No Explorador de Pontos de Extremidade, clique com o botão direito do rato no primeiro ponto de extremidade GET e selecione Gerar pedido.
O seguinte conteúdo é adicionado ao arquivo
TodoApi.http:GET {{TodoApi_HostAddress}}/api/todoitems ###Selecione o link Enviar solicitação que está acima da nova
GETlinha de solicitação.A solicitação GET é enviada para o aplicativo e a resposta é exibida no painel Resposta .
O corpo da resposta é semelhante ao seguinte JSON:
[ { "id": 1, "name": "walk dog", "isComplete": true } ]No Explorador de Endpoints, clique com o botão direito do rato no
/api/todoitems/{id}endpoint GET e selecionar Gerar pedido. 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 que está acima da nova linha de solicitação GET.
A solicitação GET é enviada para o 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
Estão implementados dois endpoints GET.
GET /api/todoitemsGET /api/todoitems/{id}
A seção anterior mostrou um exemplo da /api/todoitems/{id} rota.
Siga as instruções do POST para adicionar outro item todo e teste a rota usando o /api/todoitems Swagger.
Este aplicativo usa um banco de dados na 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 POST para a aplicação.
Roteamento e caminhos de URL
O [HttpGet] atributo denota um método que responde a uma HTTP GET solicitação. O caminho da URL para cada método é construído da seguinte maneira:
Comece com a cadeia de caracteres do modelo no atributo do controlador
Route.[Route("api/[controller]")] [ApiController] public class TodoItemsController : ControllerBaseSubstitua
[controller]pelo nome do controlador, que por convenção é o nome da classe do controlador menos o sufixo "Controller". Para este exemplo, o nome da classe do controlador é TodoItemsController, portanto, o nome do controlador é "TodoItems". ASP.NET O roteamento principal não diferencia maiúsculas de minúsculas.Se o
[HttpGet]atributo tiver um modelo de rota (por exemplo,[HttpGet("products")]), acrescente-o ao caminho. Este exemplo não usa um modelo. Para obter mais informações, consulte Roteamento de atributos com atributos Http[Verb].
No método a seguir GetTodoItem , "{id}" é uma variável de espaço reservado para o identificador exclusivo do item to-do. Quando GetTodoItem é invocado, o valor de "{id}" na URL é fornecido para o método em seu id parâmetro.
[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 de retorno
O tipo de retorno dos métodos GetTodoItems e GetTodoItem é o tipo ActionResult<T>. ASP.NET Core serializa automaticamente o objeto para 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 exceções não tratadas. As exceções não tratadas são traduzidas em erros 5xx.
ActionResult os tipos de retorno podem representar uma ampla gama de códigos de status HTTP. Por exemplo, GetTodoItem pode retornar dois valores de status diferentes:
- Se nenhum item corresponder à ID solicitada, o método retornará um 404 statusNotFound código de erro.
- Caso contrário, o método retorna 200 com um corpo de resposta JSON. O retorno
itemresulta em umaHTTP 200resposta.
O método PutTodoItem
Examine o PutTodoItem método:
[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 ao PostTodoItem, exceto que usa HTTP PUT. A resposta é 204 (Sem Conteúdo). De acordo com a especificação HTTP, uma PUT solicitação requer que o cliente envie toda a entidade atualizada, não apenas as alterações. Para suportar atualizações parciais, use HTTP PATCH.
Testar o método PutTodoItem
Este exemplo usa um banco de dados na memória que deve ser inicializado sempre que o aplicativo é iniciado. Deve haver um item no banco de dados antes de fazer uma chamada PUT. Chame GET para garantir que há um item no banco de dados antes de fazer uma chamada PUT.
Use o PUT método para atualizar o TodoItem que tem Id = 1 e defina seu nome como "feed fish". Observe que a resposta é HTTP 204 No Content.
No Explorador de Pontos de Extremidade, clique com o botão direito do rato no ponto de extremidade PUT e selecione Gerar pedido.
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
//TodoItempelas 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 que está acima da nova linha de solicitação PUT.
A solicitação PUT é enviada para o 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 DeleteTodoItem método:
[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 DELETE método para excluir o TodoItem que tem Id = 1. Observe que a resposta é HTTP 204 No Content.
No Endpoints Explorer, clique com o botão direito no endpoint DELETE e selecione Gerar solicitação.
Uma solicitação DELETE é adicionada ao
TodoApi.http.Substitua
{{id}}na linha de solicitação DELETE por1. A solicitação DELETE deve se parecer com o 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 para o 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 usadas para testar APIs da Web, por exemplo:
Evitar a sobrepostagem
Atualmente, o aplicativo de exemplo expõe todo o objeto TodoItem. Os aplicativos de produção normalmente limitam os dados que são inseridos e retornados 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 referido como um objeto de transferência de dados (DTO), modelo de entrada ou modelo de exibição.
DTO é usado neste tutorial.
Um DTO pode ser utilizado para:
- Evite a sobrepublicação.
- Oculte propriedades que os clientes não devem visualizar.
- Omita algumas propriedades para reduzir o tamanho da carga útil.
- Nivelar gráficos de objetos que contêm objetos aninhados. Gráficos de objetos achatados podem ser mais convenientes para os clientes.
Para demonstrar a abordagem 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 oculto deste aplicativo, mas um aplicativo administrativo pode optar por expô-lo.
Verifique se você pode postar e obter o campo secreto.
Crie um modelo 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 da Web com JavaScript
Consulte Tutorial: Chamar uma API da Web ASP.NET Core com JavaScript.
Série de vídeos da API Web
Veja Vídeo: Série para Iniciantes em APIs da Web.
Padrões de aplicativos Web corporativos
Para obter orientação sobre como criar um aplicativo ASP.NET Core confiável, seguro, com desempenho, testável e escalável, consulte Padrões de aplicativos Web corporativos. Está disponível um aplicativo Web de exemplo completo com qualidade de produção que implementa os padrões.
Adicionar suporte de autenticação a uma API da Web
O ASP.NET Core Identity adiciona a funcionalidade de login da interface do usuário (UI) aos aplicativos Web ASP.NET Core. Para proteger APIs da Web e SPAs, use uma das seguintes opções:
- Microsoft Entra ID
- Azure Ative Directory B2C (Azure AD B2C)
- Servidor Duende Identity
O Duende Identity Server é uma framework para OpenID Connect e OAuth 2.0 no ASP.NET Core. O Duende Server habilita os seguintes recursos de Identity segurança:
- Autenticação como serviço (AaaS)
- Logon único/desligamento (SSO) em vários tipos de aplicativos
- Controle de acesso para APIs
- Gateway de Federação
Important
Duende Software pode exigir que você pague uma taxa de licença para uso de produção do Duende Identity Server. Para obter mais informações, consulte Migrar do ASP.NET Core no .NET 5 para o .NET 6.
Para obter mais informações, consulte a documentação do Duende Identity Server (site da Duende Software).
Publicar no Azure
Para obter informações sobre como implantar no Azure, consulte Guia de início rápido: implantar um aplicativo Web ASP.NET.
Recursos adicionais
Veja ou descarregue o código de exemplo para este tutorial. Veja como fazer o download.
Para obter mais informações, consulte os seguintes recursos:
- Crie APIs da Web com ASP.NET Core
- Tutorial: Criar uma API mínima com ASP.NET Core
- Use os documentos OpenAPI gerados
- Documentação da ASP.NET Core web API com Swagger / OpenAPI
- Razor Páginas com 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 ASP.NET Core
- Implantar aplicativos ASP.NET Core no Serviço de Aplicativo do Azure
- Hospedar e publicar ASP.NET Core
- Criar uma API da Web com o ASP.NET Core
Este tutorial ensina os conceitos básicos da criação de uma API da 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 com a escolha entre APIs mínimas e APIs baseadas em controlador, consulte Visão geral de APIs. Para obter um tutorial sobre como criar uma API mínima, consulte Tutorial: Criar uma API mínima com o ASP.NET Core.
Overview
Este tutorial cria a seguinte API:
| API | Description | Corpo de solicitação | Corpo da resposta |
|---|---|---|---|
GET /api/todoitems |
Consiga todos os itens to-do | None | Lista de tarefas a fazer |
GET /api/todoitems/{id} |
Obter um item pelo ID | None | Item de tarefa |
POST /api/todoitems |
Adicionar um novo item | Item de tarefa | Item de tarefa |
PUT /api/todoitems/{id} |
Atualizar um item existente | Item de tarefa | None |
DELETE /api/todoitems/{id} |
Excluir um item | None | None |
O diagrama a seguir mostra o design do aplicativo.
Prerequisites
Visual Studio 2022 com a carga de trabalho ASP.NET e desenvolvimento web.
Criar um projeto Web
- No menu Arquivo, selecione Novo>Projeto.
- Digite Web API na caixa de pesquisa.
- Selecione o modelo
ASP.NET Core Web API e selecione Next . - Na caixa de diálogo Configurar seu novo projeto, nomeie o projeto como TodoApi e selecione Avançar.
- No caixa de diálogo de Informações adicionais :
- Confirme se o Framework é .NET 8.0 (Suporte de Longo Prazo).
- Confirme que a caixa de seleção Usar controladores (desmarque para usar APIs mínimas) está marcada.
- Confirme que a caixa de seleção Ativar suporte a OpenAPI está marcada.
- Selecione Criar.
Adicionar um pacote NuGet
Um pacote NuGet deve ser adicionado para dar suporte ao banco de dados usado neste tutorial.
- No menu Ferramentas, selecione Gerenciador de Pacotes NuGet > Gerenciar Pacotes NuGet para Solução.
- Selecione a guia Procurar.
- Digite Microsoft.EntityFrameworkCore.InMemory na caixa de pesquisa e selecione
Microsoft.EntityFrameworkCore.InMemory. - Marque a caixa de seleção Projeto no painel direito e selecione Instalar.
Note
Para obter orientação sobre como adicionar pacotes a aplicativos .NET, consulte os artigos na seção Instalar e gerenciar pacotes em Workflow de utilização de pacotes (documentação do NuGet). Confirme as versões corretas do pacote em NuGet.org.
Testar o projeto
O modelo de projeto cria uma WeatherForecast API com suporte para Swagger.
Pressione Ctrl+F5 para executar sem o depurador.
Visual Studio exibe a seguinte caixa de diálogo quando um projeto ainda não está configurado para usar SSL:
Selecione Sim se confiar no certificado SSL do IIS Express.
A seguinte caixa de diálogo é exibida:
Selecione Sim se concordar em confiar no certificado de desenvolvimento.
Para obter informações sobre como confiar no navegador Firefox, consulte o erro de certificado SEC_ERROR_INADEQUATE_KEY_USAGE do Firefox na secção .
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 definido na criação do projeto.
A página Swagger /swagger/index.html é 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 de resposta, o corpo e os cabeçalhos.
- Uma caixa de listagem suspensa com tipos de media, valor de exemplo e esquema.
Se a página Swagger não aparecer, consulte este problema do GitHub.
Swagger é usado para gerar documentação útil e páginas de ajuda para APIs da web. Este tutorial usa o Swagger para testar o aplicativo. Para obter mais informações sobre Swagger, consulte documentação da API Web do ASP.NET Core com Swagger / OpenAPI.
Copie e cole o URL de solicitação no navegador: https://localhost:<port>/weatherforecast
JSON semelhante ao exemplo a seguir é retornado:
[
{
"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 que o aplicativo gerencia. O modelo para este aplicativo é a TodoItem classe.
- No Gerenciador de Soluções , clique com o botão direito do mouse no projeto. Selecione Adicionar>Nova Pasta. Dê um nome à pasta
Models. - Clique com o botão direito do mouse na
Modelspasta e selecione Adicionar>classe. Nomeie a classe 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 Id propriedade funciona como a chave exclusiva em um banco de dados relacional.
As classes de modelo podem ir para qualquer lugar no projeto, mas a Models pasta é usada por convenção.
Adicionar um contexto de banco de dados
O contexto do banco de dados é a classe principal que coordena a funcionalidade do Entity Framework para um modelo de dados. Essa classe é criada derivando da classe Microsoft.EntityFrameworkCore.DbContext.
- Clique com o botão direito do mouse na
Modelspasta e selecione Adicionar>classe. Nomeie a classe 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 do banco de dados
No ASP.NET Core, serviços como o contexto de banco de dados devem ser registrados com o 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 destacado:
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:
- Acrescenta
usingdiretivas. - Adiciona o contexto do banco de dados ao contêiner DI.
- Especifica que o contexto do banco de dados usará um banco de dados na memória.
Andaime um controlador
Clique com o botão direito do rato 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 Model.
- Selecione TodoContext (TodoApi.Models) na classe de contexto Data.
- Selecione Adicionar.
Se a operação de andaime falhar, selecione Adicionar para tentar andaimes uma segunda vez.
O código gerado:
- Marca a classe com o
[ApiController]atributo. Esse atributo indica que o controlador responde a solicitações de API da Web. Para obter informações sobre comportamentos específicos habilitados pelo atributo, consulte Criar APIs da Web com ASP.NET Core. - Usa DI para injetar o contexto da base de dados (
TodoContext) no controlador. O contexto do banco de dados é usado em cada um dos métodos CRUD no controlador.
Os modelos ASP.NET Core para:
- Os controladores com views incluem
[action]no modelo de rota. - Os controladores de API não incluem
[action]no modelo de rota.
Quando o [action] token não está no modelo de rota, o nome da ação (nome do método) não é incluído no ponto de extremidade. Ou seja, o nome do método associado à ação não é usado na rota correspondente.
Atualizar o método de criação PostTodoItem
Atualize a instrução de retorno 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 HTTP POST método, conforme indicado pelo [HttpPost] atributo. O método obtém o valor do TodoItem do corpo da solicitação HTTP.
Para obter mais informações, consulte Roteamento de atributos com atributos Http[Verb].
O método CreatedAtAction:
- Retorna um código de status HTTP 201 se for bem-sucedido.
HTTP 201é a resposta padrão para umHTTP POSTmétodo que cria um novo recurso no servidor. - Adiciona um cabeçalho Location à resposta. O
Locationcabeçalho especifica o URI do item to-do recém-criado. Para obter mais informações, consulte 10.2.2 201 Criado. - Faz referência à ação
GetTodoItempara criar o URI do cabeçalhoLocation. A palavra-chave C#nameofé usada para evitar a codificação direta do nome da ação na chamadaCreatedAtAction.
Teste PostTodoItem
Pressione Ctrl+F5 para executar o aplicativo.
Na janela do navegador Swagger, selecione POST /api/TodoItems e, em seguida, selecione Experimentar.
Na janela Solicitar corpo de entrada, atualize o JSON. Por exemplo
{ "name": "walk dog", "isComplete": true }Selecione Executar
Testar o URI do cabeçalho de localização
No POST anterior, a interface Swagger mostra o cabeçalho de localização em Cabeçalhos de resposta. Por exemplo, location: https://localhost:7260/api/TodoItems/1. O cabeçalho de localização mostra o endereç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, em seguida, selecione Experimentar.
Entre
1naidcaixa de entrada e selecione Executar.
Examine os métodos GET
Estão implementados dois endpoints GET.
GET /api/todoitemsGET /api/todoitems/{id}
A seção anterior mostrou um exemplo da /api/todoitems/{id} rota.
Siga as instruções do POST para adicionar outro item todo e teste a rota usando o /api/todoitems Swagger.
Este aplicativo usa um banco de dados na 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 POST para a aplicação.
Roteamento e caminhos de URL
O [HttpGet] atributo denota um método que responde a uma HTTP GET solicitação. O caminho da URL para cada método é construído da seguinte maneira:
Comece com a cadeia de caracteres do modelo no atributo do controlador
Route.[Route("api/[controller]")] [ApiController] public class TodoItemsController : ControllerBaseSubstitua
[controller]pelo nome do controlador, que por convenção é o nome da classe do controlador menos o sufixo "Controller". Para este exemplo, o nome da classe do controlador é TodoItemsController, portanto, o nome do controlador é "TodoItems". ASP.NET O roteamento principal não diferencia maiúsculas de minúsculas.Se o
[HttpGet]atributo tiver um modelo de rota (por exemplo,[HttpGet("products")]), acrescente-o ao caminho. Este exemplo não usa um modelo. Para obter mais informações, consulte Roteamento de atributos com atributos Http[Verb].
No método a seguir GetTodoItem , "{id}" é uma variável de espaço reservado para o identificador exclusivo do item to-do. Quando GetTodoItem é invocado, o valor de "{id}" na URL é fornecido para o método em seu id parâmetro.
[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 de retorno
O tipo de retorno dos métodos GetTodoItems e GetTodoItem é o tipo ActionResult<T>. ASP.NET Core serializa automaticamente o objeto para 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 exceções não tratadas. As exceções não tratadas são traduzidas em erros 5xx.
ActionResult os tipos de retorno podem representar uma ampla gama de códigos de status HTTP. Por exemplo, GetTodoItem pode retornar dois valores de status diferentes:
- Se nenhum item corresponder à ID solicitada, o método retornará um 404 statusNotFound código de erro.
- Caso contrário, o método retorna 200 com um corpo de resposta JSON. O retorno
itemresulta em umaHTTP 200resposta.
O método PutTodoItem
Examine o PutTodoItem método:
[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 ao PostTodoItem, exceto que usa HTTP PUT. A resposta é 204 (Sem Conteúdo). De acordo com a especificação HTTP, uma PUT solicitação requer que o cliente envie toda a entidade atualizada, não apenas as alterações. Para suportar atualizações parciais, use HTTP PATCH.
Testar o método PutTodoItem
Este exemplo usa um banco de dados na memória que deve ser inicializado sempre que o aplicativo é iniciado. Deve haver um item no banco de dados antes de fazer uma chamada PUT. Chame GET para garantir que há 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 defina seu nome como "feed fish". Observe que a resposta é HTTP 204 No Content.
O método DeleteTodoItem
Examine o DeleteTodoItem método:
[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
Utilize a interface Swagger para apagar o TodoItem que tem o Id = 1. Observe que a resposta é HTTP 204 No Content.
Teste com outras ferramentas
Existem muitas outras ferramentas que podem ser usadas para testar APIs da Web, por exemplo:
- Visual Studio Endpoints Explorer e arquivos .http
- http-repl
-
curl. O Swagger usa
curle mostra os comandos quecurlenvia. - Fiddler
Para obter mais informações, consulte:
Evitar a sobrepostagem
Atualmente, o aplicativo de exemplo expõe todo o objeto TodoItem. Os aplicativos de produção normalmente limitam os dados que são inseridos e retornados 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 referido como um objeto de transferência de dados (DTO), modelo de entrada ou modelo de exibição.
DTO é usado neste tutorial.
Um DTO pode ser utilizado para:
- Evite a sobrepublicação.
- Oculte propriedades que os clientes não devem visualizar.
- Omita algumas propriedades para reduzir o tamanho da carga útil.
- Nivelar gráficos de objetos que contêm objetos aninhados. Gráficos de objetos achatados podem ser mais convenientes para os clientes.
Para demonstrar a abordagem 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 oculto deste aplicativo, mas um aplicativo administrativo pode optar por expô-lo.
Verifique se você pode postar e obter o campo secreto.
Crie um modelo 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 da Web com JavaScript
Consulte Tutorial: Chamar uma API da Web ASP.NET Core com JavaScript.
Série de vídeos da API Web
Veja Vídeo: Série para Iniciantes em APIs da Web.
Padrões de aplicativos Web corporativos
Para obter orientação sobre como criar um aplicativo ASP.NET Core confiável, seguro, com desempenho, testável e escalável, consulte Padrões de aplicativos Web corporativos. Está disponível um aplicativo Web de exemplo completo com qualidade de produção que implementa os padrões.
Adicionar suporte de autenticação a uma API da Web
O ASP.NET Core Identity adiciona a funcionalidade de login da interface do usuário (UI) aos aplicativos Web ASP.NET Core. Para proteger APIs da Web e SPAs, use uma das seguintes opções:
- Microsoft Entra ID
- Azure Ative Directory B2C (Azure AD B2C)
- Servidor Duende Identity
O Duende Identity Server é uma framework para OpenID Connect e OAuth 2.0 no ASP.NET Core. O Duende Server habilita os seguintes recursos de Identity segurança:
- Autenticação como serviço (AaaS)
- Logon único/desligamento (SSO) em vários tipos de aplicativos
- Controle de acesso para APIs
- Gateway de Federação
Important
Duende Software pode exigir que você pague uma taxa de licença para uso de produção do Duende Identity Server. Para obter mais informações, consulte Migrar do ASP.NET Core no .NET 5 para o .NET 6.
Para obter mais informações, consulte a documentação do Duende Identity Server (site da Duende Software).
Publicar no Azure
Para obter informações sobre como implantar no Azure, consulte Guia de início rápido: implantar um aplicativo Web ASP.NET.
Recursos adicionais
Veja ou descarregue o código de exemplo para este tutorial. Veja como fazer o download.
Para obter mais informações, consulte os seguintes recursos:
- Crie APIs da Web com ASP.NET Core
- Tutorial: Criar uma API mínima com ASP.NET Core
- Documentação da ASP.NET Core web API com Swagger / OpenAPI
- Razor Páginas com 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 ASP.NET Core
- Implantar aplicativos ASP.NET Core no Serviço de Aplicativo do Azure
- Hospedar e publicar ASP.NET Core
- Criar uma API da Web com o ASP.NET Core
Este tutorial ensina os conceitos básicos da criação de uma API da 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 com a escolha entre APIs mínimas e APIs baseadas em controlador, consulte Visão geral de APIs. Para obter um tutorial sobre como criar uma API mínima, consulte Tutorial: Criar uma API mínima com o ASP.NET Core.
Overview
Este tutorial cria a seguinte API:
| API | Description | Corpo de solicitação | Corpo da resposta |
|---|---|---|---|
GET /api/todoitems |
Consiga todos os itens to-do | None | Lista de tarefas a fazer |
GET /api/todoitems/{id} |
Obter um item pelo ID | None | Item de tarefa |
POST /api/todoitems |
Adicionar um novo item | Item de tarefa | Item de tarefa |
PUT /api/todoitems/{id} |
Atualizar um item existente | Item de tarefa | None |
DELETE /api/todoitems/{id} |
Excluir um item | None | None |
O diagrama a seguir mostra o design do aplicativo.
Prerequisites
Visual Studio 2022 com a carga de trabalho ASP.NET e desenvolvimento web.
Criar um projeto Web
- No menu Arquivo, selecione Novo>Projeto.
- Digite Web API na caixa de pesquisa.
- Selecione o modelo
ASP.NET Core Web API e selecione Next . - Na caixa de diálogo Configurar seu novo projeto, nomeie o projeto como TodoApi e selecione Avançar.
- No caixa de diálogo de Informações adicionais :
- Confirme se o Framework é .NET 8.0 (Suporte de Longo Prazo).
- Confirme que a caixa de seleção Usar controladores (desmarque para usar APIs mínimas) está marcada.
- Confirme que a caixa de seleção Ativar suporte a OpenAPI está marcada.
- Selecione Criar.
Adicionar um pacote NuGet
Um pacote NuGet deve ser adicionado para dar suporte ao banco de dados usado neste tutorial.
- No menu Ferramentas, selecione Gerenciador de Pacotes NuGet > Gerenciar Pacotes NuGet para Solução.
- Selecione a guia Procurar.
- Digite Microsoft.EntityFrameworkCore.InMemory na caixa de pesquisa e selecione
Microsoft.EntityFrameworkCore.InMemory. - Marque a caixa de seleção Projeto no painel direito e selecione Instalar.
Note
Para obter orientação sobre como adicionar pacotes a aplicativos .NET, consulte os artigos na seção Instalar e gerenciar pacotes em Workflow de utilização de pacotes (documentação do NuGet). Confirme as versões corretas do pacote em NuGet.org.
Testar o projeto
O modelo de projeto cria uma WeatherForecast API com suporte para Swagger.
Pressione Ctrl+F5 para executar sem o depurador.
Visual Studio exibe a seguinte caixa de diálogo quando um projeto ainda não está configurado para usar SSL:
Selecione Sim se confiar no certificado SSL do IIS Express.
A seguinte caixa de diálogo é exibida:
Selecione Sim se concordar em confiar no certificado de desenvolvimento.
Para obter informações sobre como confiar no navegador Firefox, consulte o erro de certificado SEC_ERROR_INADEQUATE_KEY_USAGE do Firefox na secção .
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 definido na criação do projeto.
A página Swagger /swagger/index.html é 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 de resposta, o corpo e os cabeçalhos.
- Uma caixa de listagem suspensa com tipos de media, valor de exemplo e esquema.
Se a página Swagger não aparecer, consulte este problema do GitHub.
Swagger é usado para gerar documentação útil e páginas de ajuda para APIs da web. Este tutorial usa o Swagger para testar o aplicativo. Para obter mais informações sobre Swagger, consulte documentação da API Web do ASP.NET Core com Swagger / OpenAPI.
Copie e cole o URL de solicitação no navegador: https://localhost:<port>/weatherforecast
JSON semelhante ao exemplo a seguir é retornado:
[
{
"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 que o aplicativo gerencia. O modelo para este aplicativo é a TodoItem classe.
- No Gerenciador de Soluções , clique com o botão direito do mouse no projeto. Selecione Adicionar>Nova Pasta. Dê um nome à pasta
Models. - Clique com o botão direito do mouse na
Modelspasta e selecione Adicionar>classe. Nomeie a classe 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 Id propriedade funciona como a chave exclusiva em um banco de dados relacional.
As classes de modelo podem ir para qualquer lugar no projeto, mas a Models pasta é usada por convenção.
Adicionar um contexto de banco de dados
O contexto do banco de dados é a classe principal que coordena a funcionalidade do Entity Framework para um modelo de dados. Essa classe é criada derivando da classe Microsoft.EntityFrameworkCore.DbContext.
- Clique com o botão direito do mouse na
Modelspasta e selecione Adicionar>classe. Nomeie a classe 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 do banco de dados
No ASP.NET Core, serviços como o contexto de banco de dados devem ser registrados com o 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 destacado:
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:
- Acrescenta
usingdiretivas. - Adiciona o contexto do banco de dados ao contêiner DI.
- Especifica que o contexto do banco de dados usará um banco de dados na memória.
Andaime um controlador
Clique com o botão direito do rato 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 Model.
- Selecione TodoContext (TodoApi.Models) na classe de contexto Data.
- Selecione Adicionar.
Se a operação de andaime falhar, selecione Adicionar para tentar andaimes uma segunda vez.
O código gerado:
- Marca a classe com o
[ApiController]atributo. Esse atributo indica que o controlador responde a solicitações de API da Web. Para obter informações sobre comportamentos específicos habilitados pelo atributo, consulte Criar APIs da Web com ASP.NET Core. - Usa DI para injetar o contexto da base de dados (
TodoContext) no controlador. O contexto do banco de dados é usado em cada um dos métodos CRUD no controlador.
Os modelos ASP.NET Core para:
- Os controladores com views incluem
[action]no modelo de rota. - Os controladores de API não incluem
[action]no modelo de rota.
Quando o [action] token não está no modelo de rota, o nome da ação (nome do método) não é incluído no ponto de extremidade. Ou seja, o nome do método associado à ação não é usado na rota correspondente.
Atualizar o método de criação PostTodoItem
Atualize a instrução de retorno 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 HTTP POST método, conforme indicado pelo [HttpPost] atributo. O método obtém o valor do TodoItem do corpo da solicitação HTTP.
Para obter mais informações, consulte Roteamento de atributos com atributos Http[Verb].
O método CreatedAtAction:
- Retorna um código de status HTTP 201 se for bem-sucedido.
HTTP 201é a resposta padrão para umHTTP POSTmétodo que cria um novo recurso no servidor. - Adiciona um cabeçalho Location à resposta. O
Locationcabeçalho especifica o URI do item to-do recém-criado. Para obter mais informações, consulte 10.2.2 201 Criado. - Faz referência à ação
GetTodoItempara criar o URI do cabeçalhoLocation. A palavra-chave C#nameofé usada para evitar a codificação direta do nome da ação na chamadaCreatedAtAction.
Teste PostTodoItem
Pressione Ctrl+F5 para executar o aplicativo.
Na janela do navegador Swagger, selecione POST /api/TodoItems e, em seguida, selecione Experimentar.
Na janela Solicitar corpo de entrada, atualize o JSON. Por exemplo
{ "name": "walk dog", "isComplete": true }Selecione Executar
Testar o URI do cabeçalho de localização
No POST anterior, a interface Swagger mostra o cabeçalho de localização em Cabeçalhos de resposta. Por exemplo, location: https://localhost:7260/api/TodoItems/1. O cabeçalho de localização mostra o endereç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, em seguida, selecione Experimentar.
Entre
1naidcaixa de entrada e selecione Executar.
Examine os métodos GET
Estão implementados dois endpoints GET.
GET /api/todoitemsGET /api/todoitems/{id}
A seção anterior mostrou um exemplo da /api/todoitems/{id} rota.
Siga as instruções do POST para adicionar outro item todo e teste a rota usando o /api/todoitems Swagger.
Este aplicativo usa um banco de dados na 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 POST para a aplicação.
Roteamento e caminhos de URL
O [HttpGet] atributo denota um método que responde a uma HTTP GET solicitação. O caminho da URL para cada método é construído da seguinte maneira:
Comece com a cadeia de caracteres do modelo no atributo do controlador
Route.[Route("api/[controller]")] [ApiController] public class TodoItemsController : ControllerBaseSubstitua
[controller]pelo nome do controlador, que por convenção é o nome da classe do controlador menos o sufixo "Controller". Para este exemplo, o nome da classe do controlador é TodoItemsController, portanto, o nome do controlador é "TodoItems". ASP.NET O roteamento principal não diferencia maiúsculas de minúsculas.Se o
[HttpGet]atributo tiver um modelo de rota (por exemplo,[HttpGet("products")]), acrescente-o ao caminho. Este exemplo não usa um modelo. Para obter mais informações, consulte Roteamento de atributos com atributos Http[Verb].
No método a seguir GetTodoItem , "{id}" é uma variável de espaço reservado para o identificador exclusivo do item to-do. Quando GetTodoItem é invocado, o valor de "{id}" na URL é fornecido para o método em seu id parâmetro.
[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 de retorno
O tipo de retorno dos métodos GetTodoItems e GetTodoItem é o tipo ActionResult<T>. ASP.NET Core serializa automaticamente o objeto para 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 exceções não tratadas. As exceções não tratadas são traduzidas em erros 5xx.
ActionResult os tipos de retorno podem representar uma ampla gama de códigos de status HTTP. Por exemplo, GetTodoItem pode retornar dois valores de status diferentes:
- Se nenhum item corresponder à ID solicitada, o método retornará um 404 statusNotFound código de erro.
- Caso contrário, o método retorna 200 com um corpo de resposta JSON. O retorno
itemresulta em umaHTTP 200resposta.
O método PutTodoItem
Examine o PutTodoItem método:
[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 ao PostTodoItem, exceto que usa HTTP PUT. A resposta é 204 (Sem Conteúdo). De acordo com a especificação HTTP, uma PUT solicitação requer que o cliente envie toda a entidade atualizada, não apenas as alterações. Para suportar atualizações parciais, use HTTP PATCH.
Testar o método PutTodoItem
Este exemplo usa um banco de dados na memória que deve ser inicializado sempre que o aplicativo é iniciado. Deve haver um item no banco de dados antes de fazer uma chamada PUT. Chame GET para garantir que há 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 defina seu nome como "feed fish". Observe que a resposta é HTTP 204 No Content.
O método DeleteTodoItem
Examine o DeleteTodoItem método:
[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
Utilize a interface Swagger para apagar o TodoItem que tem o Id = 1. Observe que a resposta é HTTP 204 No Content.
Teste com outras ferramentas
Existem muitas outras ferramentas que podem ser usadas para testar APIs da Web, por exemplo:
- Visual Studio Endpoints Explorer e arquivos .http
- http-repl
-
curl. O Swagger usa
curle mostra os comandos quecurlenvia. - Fiddler
Para obter mais informações, consulte:
Evitar a sobrepostagem
Atualmente, o aplicativo de exemplo expõe todo o objeto TodoItem. Os aplicativos de produção normalmente limitam os dados que são inseridos e retornados 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 referido como um objeto de transferência de dados (DTO), modelo de entrada ou modelo de exibição.
DTO é usado neste tutorial.
Um DTO pode ser utilizado para:
- Evite a sobrepublicação.
- Oculte propriedades que os clientes não devem visualizar.
- Omita algumas propriedades para reduzir o tamanho da carga útil.
- Nivelar gráficos de objetos que contêm objetos aninhados. Gráficos de objetos achatados podem ser mais convenientes para os clientes.
Para demonstrar a abordagem 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 oculto deste aplicativo, mas um aplicativo administrativo pode optar por expô-lo.
Verifique se você pode postar e obter o campo secreto.
Crie um modelo 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 da Web com JavaScript
Consulte Tutorial: Chamar uma API da Web ASP.NET Core com JavaScript.
Série de vídeos da API Web
Veja Vídeo: Série para Iniciantes em APIs da Web.
Padrões de aplicativos Web corporativos
Para obter orientação sobre como criar um aplicativo ASP.NET Core confiável, seguro, com desempenho, testável e escalável, consulte Padrões de aplicativos Web corporativos. Está disponível um aplicativo Web de exemplo completo com qualidade de produção que implementa os padrões.
Adicionar suporte de autenticação a uma API da Web
O ASP.NET Core Identity adiciona a funcionalidade de login da interface do usuário (UI) aos aplicativos Web ASP.NET Core. Para proteger APIs da Web e SPAs, use uma das seguintes opções:
- Microsoft Entra ID
- Azure Ative Directory B2C (Azure AD B2C)
- Servidor Duende Identity
O Duende Identity Server é uma framework para OpenID Connect e OAuth 2.0 no ASP.NET Core. O Duende Server habilita os seguintes recursos de Identity segurança:
- Autenticação como serviço (AaaS)
- Logon único/desligamento (SSO) em vários tipos de aplicativos
- Controle de acesso para APIs
- Gateway de Federação
Important
Duende Software pode exigir que você pague uma taxa de licença para uso de produção do Duende Identity Server. Para obter mais informações, consulte Migrar do ASP.NET Core no .NET 5 para o .NET 6.
Para obter mais informações, consulte a documentação do Duende Identity Server (site da Duende Software).
Publicar no Azure
Para obter informações sobre como implantar no Azure, consulte Guia de início rápido: implantar um aplicativo Web ASP.NET.
Recursos adicionais
Veja ou descarregue o código de exemplo para este tutorial. Veja como fazer o download.
Para obter mais informações, consulte os seguintes recursos:
- Crie APIs da Web com ASP.NET Core
- Tutorial: Criar uma API mínima com ASP.NET Core
- Documentação da ASP.NET Core web API com Swagger / OpenAPI
- Razor Páginas com 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 ASP.NET Core
- Implantar aplicativos ASP.NET Core no Serviço de Aplicativo do Azure
- Hospedar e publicar ASP.NET Core
- Criar uma API da Web com o ASP.NET Core