Pular para o conteúdo
.NETDTOs e AutoMapper
Módulo 03Construindo a Web API

DTOs e AutoMapper

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

DTOs (Data Transfer Objects) definem o contrato público da API, separado das entidades de domínio. O AutoMapper reduz o código repetitivo de mapeamento entre entidade e DTO.

Nota

a partir da v15.0.0 (2 de julho de 2025, Lucky Penny Software), o AutoMapper adota modelo comercial para uso empresarial. A v14.x (última livre, MIT) permanece gratuita. Avalie a licença antes de adotar a v15+ em produção; alternativas open-source incluem mapeamento manual ou geradores de código em tempo de compilação (ex.: Mapperly, MIT). Os conceitos de DTO e mapeamento desta aula valem para qualquer abordagem.

1. Objetivos de Aprendizagem#

  • Explicar por que DTOs e entidades devem ser distintos.
  • Criar DTOs de leitura (records).
  • Configurar e usar o AutoMapper.

2. Pré-requisitos#

  • Endpoint GET retornando entidades (tópico 18.2).

3. Conceito#

DTO vs. Entidade: a entidade modela persistência e regras de negócio; o DTO modela o contrato de transporte. Separá-los evita: vazamento de campos internos, loops de serialização, e acoplamento do cliente à estrutura do banco. O porquê: você pode evoluir o schema do banco sem quebrar clientes, e vice-versa.

record é ideal para DTOs de leitura: imutável e com igualdade por valor.

4. Mão na Massa#

4.1. Setup#

Shell
dotnet add Catalog.Api package AutoMapper
Nota

a partir das versões recentes, o pacote AutoMapper já inclui a integração com DI; não é necessário o antigo AutoMapper.Extensions.Microsoft.DependencyInjection separado.

4.2. Implementação Passo a Passo#

  1. DTO como record:
C#
namespace Catalog.Shared.DataTransferObjects;

public record CategoriaDto(Guid Id, string Nome, int QuantidadeProdutos);
  1. Perfil de mapeamento:
C#
using AutoMapper;
using Catalog.Entities.Models;

public class MappingProfile : Profile
{
    public MappingProfile()
    {
        CreateMap<Categoria, CategoriaDto>()
            .ForCtorParam(nameof(CategoriaDto.QuantidadeProdutos),
                          opt => opt.MapFrom(src => src.Produtos.Count));
    }
}
  1. Registro:
C#
builder.Services.AddAutoMapper(typeof(MappingProfile));
  1. Uso no serviço/controller:
C#
var categorias = await _repo.Categoria.GetAllAsync(trackChanges: false);
var dtos = _mapper.Map<IEnumerable<CategoriaDto>>(categorias);
return Ok(dtos);

4.3. Executando#

Shell
dotnet run
curl http://localhost:5000/api/categorias

Agora a resposta traz apenas os campos do DTO.

5. Exemplo Completo#

C#
[HttpGet]
public async Task<IActionResult> GetCategorias()
{
    var categorias = await _service.Categoria.GetAllAsync(trackChanges: false);
    return Ok(categorias); // serviço já retorna IEnumerable<CategoriaDto>
}

6. Boas Práticas e Armadilhas#

FaçaEvite
Usar DTOs distintos para leitura e escritaReusar a entidade como corpo de request/response
Validar os perfis do AutoMapper em testes (AssertConfigurationIsValid)Mapeamentos silenciosamente incompletos
Preferir records para DTOs imutáveisClasses mutáveis com setters públicos em DTOs de leitura
Atenção

AutoMapper mal configurado pode mascarar bugs (campos não mapeados viram default). Rode configuration.AssertConfigurationIsValid() num teste para garantir cobertura.

7. Segurança e Produção#

  • DTOs de escrita evitam over-posting: o cliente não consegue setar campos que não estão no DTO (ex.: IsAdmin).
  • Nunca inclua dados sensíveis em DTOs de resposta pública.

8. Exercícios#

  • Fácil: crie ProdutoDto e mapeie a partir de Produto.
  • Médio: adicione um record ProdutoForCreationDto (só campos de entrada).
  • Desafio: escreva um teste que falhe se um novo campo da entidade não tiver mapeamento correspondente.

9. Resumo#

DTOs separam o contrato da API do domínio, evitando vazamentos e over-posting. O AutoMapper elimina o mapeamento manual, mas deve ser validado por testes.

10. Próximos Passos#

Módulo 19: tratamento global de erros com middleware e ProblemDetails.

11. Referências#

18-03 — DTOs e AutoMapper | Curso ASP.NET Core