In a modern ASP.NET application, a clear separation between what comes from outside (DTO – Data Transfer Object) and our domain models (Domain Models) is an essential good practice. This separation allows validation, control of exposed data, and adherence to DDD (Domain-Driven Design) principles.
🎯 Objective
Let's use AutoMapper to transform:
-
CreatePostDto → Post – in the case of commands (write),
-
Post → PostDto – in the case of API responses (read).
🧱 Class structure
🔁 AutoMapper configuration
Install the package:
dotnet add package AutoMapper.Extensions.Microsoft.DependencyInjection
✅ Mapping profile
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))));
}
}
🧩 Registration in the DI container
builder.Services.AddAutoMapper(typeof(PostMappingProfile));
🛠️ Usage in 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;
}
}
📤 Usage when returning data (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);
}
🧠 Conclusions
-
AutoMapper eliminates manual mapping, keeping the code clean and scalable.
-
It allows us to clearly define what data we accept and what data we expose.
-
We ensure that our domain models remain independent of the API structure.