Pular para o conteúdo
.NETArmadilhas comuns
Módulo 04CRUD Completo e Validação

Armadilhas comuns

avancado 20 min de leitura·Atualizado · .NET 9
Resumo

Assincronismo mal usado gera deadlocks, exceções engolidas e uso concorrente indevido do DbContext. Este tópico reúne as armadilhas mais frequentes e como evitá-las.

1. Objetivos de Aprendizagem#

  • Reconhecer e evitar deadlocks por bloqueio síncrono.
  • Entender por que DbContext não é thread-safe.
  • Usar Task.WhenAll corretamente (e quando não usar).

2. Pré-requisitos#

  • Refatoração assíncrona (tópico 28.2).

3. Conceito#

Assincronismo tem armadilhas sutis. O porquê de estudá-las: os bugs aparecem sob carga, não em testes locais simples, e são difíceis de diagnosticar.

4. Mão na Massa#

4.1. Setup#

Conceitual, com exemplos comentados.

4.2. Implementação Passo a Passo#

  1. Deadlock por bloqueio:
C#
// RUIM: pode travar
var resultado = _service.GetAsync().Result;

// BOM
var resultado = await _service.GetAsync();
  1. DbContext não é thread-safe — não dispare consultas paralelas no mesmo contexto:
C#
// RUIM: duas consultas concorrentes no mesmo DbContext
var t1 = _repo.Categoria.GetAllAsync(false);
var t2 = _repo.Produto.GetAllAsync(false);
await Task.WhenAll(t1, t2); // pode lançar InvalidOperationException

// BOM: sequencial no mesmo contexto, ou contextos separados via IDbContextFactory
var categorias = await _repo.Categoria.GetAllAsync(false);
var produtos   = await _repo.Produto.GetAllAsync(false);
  1. Exceção engolida por async void:
C#
// RUIM: exceção não pode ser capturada por quem chama
public async void Processar() { throw new InvalidOperationException(); }

// BOM
public async Task ProcessarAsync() { /* ... */ }

4.3. Executando#

Reproduza o cenário do DbContext concorrente para ver a InvalidOperationException (A second operation was started on this context...).

5. Exemplo Completo#

Quando Task.WhenAll é adequado: chamadas independentes a serviços externos (HTTP), não ao mesmo DbContext.

C#
var t1 = _httpClient.GetAsync(urlA);
var t2 = _httpClient.GetAsync(urlB);
await Task.WhenAll(t1, t2);

6. Boas Práticas e Armadilhas#

FaçaEvite
Sempre await em vez de .Result/.Wait()Bloquear a thread e arriscar deadlock
Uma operação por vez em um DbContextParalelizar consultas no mesmo contexto
Task em vez de async voidPerder exceções silenciosamente
Atenção

IDbContextFactory<T> permite criar contextos independentes para paralelismo real, mas cada contexto tem seu próprio ciclo de vida — descarte-os corretamente.

7. Segurança e Produção#

  • Deadlocks e vazamento de conexões se manifestam como esgotamento do pool sob carga — monitore contadores de conexão e latência.

8. Exercícios#

  • Fácil: corrija um trecho que usa .Result.
  • Médio: reproduza e explique o erro de DbContext concorrente.
  • Desafio: implemente paralelismo seguro com IDbContextFactory.

9. Resumo#

Evite .Result/.Wait(), nunca use o mesmo DbContext em paralelo e prefira Task a async void. Task.WhenAll só para operações realmente independentes.

10. Próximos Passos#

Módulo 29: Action Filters para lógica transversal (cross-cutting).

11. Referências#

28-03 — Armadilhas comuns | Curso ASP.NET Core