This Gist explores three mapping strategies in .NET: AutoMapper, Manual Mapping, and Mapster. Includes benchmarks and testing guidance.
// Create an AutoMapper profile for mapping Product to ProductDto
public class ProductProfile : Profile
{
public ProductProfile()
{
CreateMap<Product, ProductDto>();
}
}// Extension method for clean, explicit mapping from Product to ProductDto
public static class ProductMapper
{
public static ProductDto ToDto(this Product p) =>
new ProductDto
{
Id = p.Id,
Name = p.Name,
Price = p.Price
};
}β Benefits:
- Compile-time safety
- Refactorable and searchable in IDE
- Simple to test
// Using Mapster's fluent config to map properties explicitly
TypeAdapterConfig<Product, ProductDto>.NewConfig()
.Map(dest => dest.Name, src => src.ProductName)
.Map(dest => dest.Price, src => src.Price);β‘ Fast and clear β ideal for repetitive and performance-sensitive mapping.
// BenchmarkDotNet-based mapping performance comparison
[MemoryDiagnoser]
public class MappingBenchmarks
{
private readonly Product _product = new() { Id = 1, Name = "Laptop", Price = 999 };
[Benchmark]
public ProductDto ManualMapping() => _product.ToDto(); // Fastest
[Benchmark]
public ProductDto MapsterMapping() => _product.Adapt<ProductDto>(); // Balanced
[Benchmark]
public ProductDto AutoMapperMapping()
{
var config = new MapperConfiguration(cfg => cfg.CreateMap<Product, ProductDto>());
var mapper = config.CreateMapper();
return mapper.Map<ProductDto>(_product); // Slowest
}
}π§ͺ Run it with:
BenchmarkRunner.Run<MappingBenchmarks>();// Basic test to ensure mapping outputs expected values
[Fact]
public void MapsProductToDto_Correctly()
{
var product = new Product { Id = 1, Name = "Laptop", Price = 999 };
var dto = product.ToDto();
dto.Id.ShouldBe(1);
dto.Name.ShouldBe("Laptop");
dto.Price.ShouldBe(999);
}public class Order { public Customer Customer { get; set; } }
public class OrderDto { public string CustomerName { get; set; } }π This won't map unless nested mapping is manually configured β easy to miss.
cfg.CreateMap<Product, ProductDto>().ReverseMap();public string? Name { get; set; } // Source
public string Name { get; set; } // Destinationπ₯ No compiler error, but potential null reference runtime bugs.
// Donβt map inline in LINQ Select when debugging or tracing
var dtos = products.Select(p => _mapper.Map<ProductDto>(p)); // β
var dtos = products.Select(p => p.ToDto()); // β
β Easier to debug, log, and maintain.
π¦ src/
β£ π Domain/
β£ π Application/
β β£ π DTOs/
β β£ π Mappers/
β£ π Benchmarks/
β£ π Tests/
MIT License Β© Yaseer Arafat