Pular para o conteúdo
.NETasync/await e tipos de retorno
Módulo 04CRUD Completo e Validação

async/await e tipos de retorno

intermediario 30 min de leitura·Atualizado · .NET 9
Resumo

Programação assíncrona libera threads durante operações de I/O (banco, rede), aumentando a escalabilidade da API. Aqui entendemos async/await, os tipos de retorno e por que "async por padrão" é a recomendação em ASP.NET Core.

1. Objetivos de Aprendizagem#

  • Explicar o que async/await resolve (escalabilidade de I/O).
  • Escolher os tipos de retorno corretos (Task, Task<T>, ValueTask).
  • Entender por que evitar bloqueio síncrono.

2. Pré-requisitos#

  • Endpoints GET (Módulo 18).

3. Conceito#

Uma operação de I/O (consulta ao banco) passa a maior parte do tempo esperando. De forma síncrona, a thread fica bloqueada esperando. Com async/await, a thread é liberada para atender outras requisições enquanto o I/O acontece, e retomada quando o resultado chega. O porquê: mais requisições atendidas com o mesmo número de threads = maior throughput.

  • Task — operação assíncrona sem valor de retorno.
  • Task<T> — operação assíncrona que produz um T.
  • ValueTask<T> — otimização para casos que frequentemente completam de forma síncrona (evita alocação).

4. Mão na Massa#

4.1. Setup#

Sem pacotes; usamos os métodos assíncronos do EF Core (ToListAsync, FirstOrDefaultAsync, SaveChangesAsync).

4.2. Implementação Passo a Passo#

  1. Método assíncrono de repositório:
C#
public async Task<IEnumerable<Categoria>> GetAllAsync(bool trackChanges) =>
    await FindAll(trackChanges).OrderBy(c => c.Nome).ToListAsync();
  1. Ação assíncrona:
C#
[HttpGet]
public async Task<IActionResult> GetCategorias()
{
    var categorias = await _service.Categoria.GetAllAsync(trackChanges: false);
    return Ok(categorias);
}
  1. ValueTask num serviço com cache que costuma responder síncrono:
C#
public ValueTask<CategoriaDto?> GetCachedAsync(Guid id) =>
    _cache.TryGetValue(id, out var dto)
        ? ValueTask.FromResult<CategoriaDto?>(dto)
        : new ValueTask<CategoriaDto?>(LoadAsync(id));

4.3. Executando#

O comportamento externo é idêntico; o ganho aparece sob carga, com maior número de requisições simultâneas atendidas.

5. Exemplo Completo#

A pilha inteira deve ser assíncrona: controller → serviço → repositório → EF Core, cada nível com await do nível seguinte.

6. Boas Práticas e Armadilhas#

FaçaEvite
Assíncrono de ponta a pontaMisturar chamadas síncronas bloqueantes no meio
Usar Task/Task nos métodos de I/Oasync void (exceto em event handlers)
Propagar CancellationTokenIgnorar cancelamento em operações longas
Atenção

async void engole exceções e não pode ser aguardado — nunca use em métodos de ação ou serviço. Use Task.

7. Segurança e Produção#

  • Propagar CancellationToken evita trabalho desperdiçado quando o cliente desiste da requisição (economia de recursos e proteção contra abuso).

8. Exercícios#

  • Fácil: converta um método de repositório síncrono para async.
  • Médio: adicione CancellationToken da ação até o ToListAsync.
  • Desafio: explique quando ValueTask traz ganho real e quando é prematuro.

9. Resumo#

async/await libera threads durante I/O, aumentando a escalabilidade. Use Task/Task<T>, evite async void e propague CancellationToken.

10. Próximos Passos#

A seguir, refatoramos repositório, serviço e controller para o modelo assíncrono.

11. Referências#

28-01 — async/await e tipos de retorno | Curso ASP.NET Core