Tutorial: criar uma API Web com o ASP.NET Core
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, confira .NET e a Política de Suporte do .NET Core. Para informações sobre a versão vigente, confira a Versão do .NET 8 deste artigo.
Importante
Essas informações relacionam-se ao produto de pré-lançamento, que poderá ser substancialmente modificado antes do lançamento comercial. A Microsoft não oferece nenhuma garantia, explícita ou implícita, quanto às informações fornecidas aqui.
Para a versão atual, consulte a versão .NET 9 deste artigo.
Por Rick Anderson e Kirk Larkin
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:
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 Procurar.
- 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 de BD precisam ser registrados no contêiner de DI (injeção de dependência). 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 de [action]
não estiver no modelo de rota, a ação nome (nome do método) não será incluída 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 local:
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
Dois pontos de extremidade GET são implementados:
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, execute POST de dados no 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 de retorno
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 404 NotFound.
- 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:
- Gerenciador de Pontos de Extremidade do Visual Studio e arquivos .http
- http-repl
- curl. O Swagger utiliza
curl
e mostra os comandoscurl
que envia. - Fiddler
Para obter mais informações, consulte:
- Tutorial da API Mínima: teste com arquivos .http e o Explorador de Pontos de Extremidade
- Instalar e testar APIs com
http-repl
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 entrada retornados pelo uso de 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 as propriedades que os clientes não devem exibir.
- 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éries iniciantes: APIs Web.
Padrões de aplicativos Web confiáveis
Confira O padrão de aplicativo da Web confiável para.NET vídeos do YouTube e artigo para obter orientação sobre como criar um aplicativo ASP.NET Core moderno, confiável, de alto desempenho, testável, econômico e escalonável, seja do zero ou refatorando um existente aplicativo.
Adicionar suporte de autenticação a uma API Web
O ASP.NET Core Identity adiciona a funcionalidade de logon da interface do usuário aos aplicativos Web do ASP.NET Core. Para proteger APIs Web e SPAs, use uma das seguintes opções:
- Microsoft Entra ID
- Azure Active Directory B2C (Azure AD B2C)
- Duende Identity Server
O Duende Identity Server é uma estrutura do OpenID Connect e OAuth 2.0 para ASP.NET Core. O Duende Identity Server habilita os seguintes recursos de segurança:
- AaaS (autenticação como serviço)
- SSO (logon único) em vários tipos de aplicativo
- Controle de acesso para APIs
- Federation Gateway
Importante
O Software Duende pode exigir que você pague uma taxa de licença pelo uso de produção do Duende Identity Server. Para obter mais informações, consulte Migrar do ASP.NET Core 5.0 para o 6.0.
Para obter mais informações, confira a documentação do Duende Identity Server (site da Duende Software).
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 Pages 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:
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 Procurar.
- 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 de BD precisam ser registrados no contêiner de DI (injeção de dependência). 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 de [action]
não estiver no modelo de rota, a ação nome (nome do método) não será incluída 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 local:
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
Dois pontos de extremidade GET são implementados:
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, execute POST de dados no 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 de retorno
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 404 NotFound.
- 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:
- Gerenciador de Pontos de Extremidade do Visual Studio e arquivos .http
- http-repl
- curl. O Swagger utiliza
curl
e mostra os comandoscurl
que envia. - Fiddler
Para obter mais informações, consulte:
- Tutorial da API Mínima: teste com arquivos .http e o Explorador de Pontos de Extremidade
- Instalar e testar APIs com
http-repl
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 entrada retornados pelo uso de 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 as propriedades que os clientes não devem exibir.
- 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éries iniciantes: APIs Web.
Padrões de aplicativos Web confiáveis
Confira O padrão de aplicativo da Web confiável para.NET vídeos do YouTube e artigo para obter orientação sobre como criar um aplicativo ASP.NET Core moderno, confiável, de alto desempenho, testável, econômico e escalonável, seja do zero ou refatorando um existente aplicativo.
Adicionar suporte de autenticação a uma API Web
O ASP.NET Core Identity adiciona a funcionalidade de logon da interface do usuário aos aplicativos Web do ASP.NET Core. Para proteger APIs Web e SPAs, use uma das seguintes opções:
- Microsoft Entra ID
- Azure Active Directory B2C (Azure AD B2C)
- Duende Identity Server
O Duende Identity Server é uma estrutura do OpenID Connect e OAuth 2.0 para ASP.NET Core. O Duende Identity Server habilita os seguintes recursos de segurança:
- AaaS (autenticação como serviço)
- SSO (logon único) em vários tipos de aplicativo
- Controle de acesso para APIs
- Federation Gateway
Importante
O Software Duende pode exigir que você pague uma taxa de licença pelo uso de produção do Duende Identity Server. Para obter mais informações, consulte Migrar do ASP.NET Core 5.0 para o 6.0.
Para obter mais informações, confira a documentação do Duende Identity Server (site da Duende Software).
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 Pages 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:
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 Procurar.
- 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 de BD precisam ser registrados no contêiner de DI (injeção de dependência). 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 de [action]
não estiver no modelo de rota, a ação nome (nome do método) não será incluída 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 local:
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
Dois pontos de extremidade GET são implementados:
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, execute POST de dados no 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 de retorno
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 404 NotFound.
- 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:
- Gerenciador de Pontos de Extremidade do Visual Studio e arquivos .http
- http-repl
- curl. O Swagger utiliza
curl
e mostra os comandoscurl
que envia. - Fiddler
Para obter mais informações, consulte:
- Tutorial da API Mínima: teste com arquivos .http e o Explorador de Pontos de Extremidade
- Instalar e testar APIs com
http-repl
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 entrada retornados pelo uso de 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 as propriedades que os clientes não devem exibir.
- 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éries iniciantes: APIs Web.
Padrões de aplicativos Web confiáveis
Confira O padrão de aplicativo da Web confiável para.NET vídeos do YouTube e artigo para obter orientação sobre como criar um aplicativo ASP.NET Core moderno, confiável, de alto desempenho, testável, econômico e escalonável, seja do zero ou refatorando um existente aplicativo.
Adicionar suporte de autenticação a uma API Web
O ASP.NET Core Identity adiciona a funcionalidade de logon da interface do usuário aos aplicativos Web do ASP.NET Core. Para proteger APIs Web e SPAs, use uma das seguintes opções:
- Microsoft Entra ID
- Azure Active Directory B2C (Azure AD B2C)
- Duende Identity Server
O Duende Identity Server é uma estrutura do OpenID Connect e OAuth 2.0 para ASP.NET Core. O Duende Identity Server habilita os seguintes recursos de segurança:
- AaaS (autenticação como serviço)
- SSO (logon único) em vários tipos de aplicativo
- Controle de acesso para APIs
- Federation Gateway
Importante
O Software Duende pode exigir que você pague uma taxa de licença pelo uso de produção do Duende Identity Server. Para obter mais informações, consulte Migrar do ASP.NET Core 5.0 para o 6.0.
Para obter mais informações, confira a documentação do Duende Identity Server (site da Duende Software).
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 Pages 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