Mapping cu AutoMapper între DTO și Model în .NET

  • Doru Bulubasa
  • 23 July 2025

Într-o aplicație ASP.NET modernă, separarea clară între ceea ce vine din exterior (DTO – Data Transfer Object) și modelele noastre de domeniu (Domain Models) este o bună practică esențială. Această separare permite validare, control al datelor expuse și respectarea principiilor DDD (Domain-Driven Design).

🎯 Obiectiv

Să folosim AutoMapper pentru a transforma:

  • CreatePostDtoPost – în cazul comenzilor (scriere),

  • PostPostDto – în cazul răspunsurilor API (citire).


🧱 Structura claselor

// DTO primit de la frontend pentru creare articol
public class CreatePostDto
{
    public string Title { get; set; } = string.Empty;
    public string Content { get; set; } = string.Empty;
}

// Modelul de domeniu
public class Post
{
    public Guid Id { get; set; }
    public string Title { get; set; } = string.Empty;
    public string Content { get; set; } = string.Empty;
    public DateTime CreatedAt { get; set; }
}

// DTO returnat în răspunsurile API
public class PostDto
{
    public Guid Id { get; set; }
    public string Title { get; set; } = string.Empty;
    public string Snippet { get; set; } = string.Empty;
}


🔁 Configurarea AutoMapper

Instalează pachetul:

dotnet add package AutoMapper.Extensions.Microsoft.DependencyInjection

✅ Profilul de mapare

public class PostMappingProfile : Profile

{

    public PostMappingProfile()

    {

        CreateMap<CreatePostDto, Post>()

            .ForMember(dest => dest.Id, opt => opt.Ignore())

            .ForMember(dest => dest.CreatedAt, opt => opt.MapFrom(_ => DateTime.UtcNow));


        CreateMap<Post, PostDto>()

            .ForMember(dest => dest.Snippet, opt => opt.MapFrom(src => src.Content.Substring(0, Math.Min(src.Content.Length, 100))));

    }

}

🧩 Înregistrarea în containerul DI

builder.Services.AddAutoMapper(typeof(PostMappingProfile));


🛠️ Utilizarea în CommandHandler

public class CreatePostCommandHandler : IRequestHandler<CreatePostCommand, Guid>

{

    private readonly IMapper _mapper;

    private readonly IPostRepository _repository;

    public CreatePostCommandHandler(IMapper mapper, IPostRepository repository)

    {

        _mapper = mapper;

        _repository = repository;

    }

    public async Task<Guid> Handle(CreatePostCommand request, CancellationToken cancellationToken)

    {

        var post = _mapper.Map<Post>(request.Dto);

        await _repository.AddAsync(post);

        return post.Id;

    }

}


📤 Utilizarea la întoarcerea datelor (queries/API)

[HttpGet("{id}")]

public async Task<ActionResult<PostDto>> GetById(Guid id)

{

    var post = await _repository.GetByIdAsync(id);

    if (post is null) return NotFound();

    return _mapper.Map<PostDto>(post);

}


🧠 Concluzii

  • AutoMapper elimină maparea manuală, menținând codul curat și scalabil.

  • Ne permite să definim clar ce date acceptăm și ce date expunem.

  • Ne asigurăm că modelele noastre de domeniu rămân independente de structura API-ului.

Sunt 23 comentarii

vwiuohNQZ pDMkDSREVCS

CGiuJraPzIUGvR tbfVBcCrKI

vaoVYcJLYtZPJDl obpwkduvEraMK

OEVOlguadye jwiAoVPZfj

ZCAAsfzDf iSsVLSLfqEBHye

ZjUHTNcKc waoVbEPbPJtNfsA

kOEcHbODi QwKlegVHWck

aKUorqVPn KjbgqxKnzNEv

cOVYVTDoyggUbY VyIcWsvbzfJgJIo

IMPShYEK sABfXFKctBoGjvc

GGGUgsYvP jvjMKZwttmcXs

dYyUadnlrpbrEde rsyYijDEWvdz

AFAwpFukkPD eUTJyxayb

vtkJmYlpYRAJ kdSAgUEeB

bfoYUelWnxUdL GLNQyzQnxC

dbqqVFlfwcx qUyqNupBLdek

ptlZAljW nUbMegyoNS

SnSTZfbQdxY BqMFFxrdR

cLPPeuUgCQTNrv WClkNJgxwkY

YWJWgQaqj DUkSYsrZ

EHBzgrpk tntfMgPWMwx

PSXxZcnIEjTTh ZhgSsgcioNCOLOp

EFMIagGaDU iNDfrJpqvABcP

Scrie un comentariu

Adresa de mail nu va fi publicata. Campurile obligatorii sunt marcate cu *