aspnet-core-mappers-automapper-mapster-benchmark

Object Mapping in .NET: AutoMapper, Mapster, or Manual

  • 4 min

An object mapper is a tool for converting objects of one type into objects of another type.

If you have followed the previous articles about DTOs, you will have encountered a repetitive and tedious task.

You have your User entity with 20 properties, and your UserDto with the same 20 properties. And you have to write this:

var dto = new UserDto
{
    FirstName = user.FirstName,
    LastName = user.LastName,
    Email = user.Email,
    // ... and so on for 17 more lines ...
};
Copied!

This is boilerplate code. It’s easy to forget a property, and when there are many mappings, it ends up cluttering the services.

Object mappers automate some of that work through conventions, compiled expressions, or code generation.

Let’s compare two common alternatives: AutoMapper and Mapster.

AutoMapper

AutoMapper is a veteran library widely used in the .NET ecosystem.

How it works

AutoMapper works based on Profiles. You must explicitly tell it which classes can be mapped to each other.

Installation

dotnet add package AutoMapper
Copied!

Profile Configuration

We create a class that inherits from Profile. Here we define the rules.

using AutoMapper;

public class MappingProfile : Profile
{
    public MappingProfile()
    {
        // Simple mapping: Properties with the same name are copied automatically
        CreateMap<Product, ProductDto>();

        // Reverse mapping (from DTO to Entity)
        CreateMap<CreateProductDto, Product>();

        // Custom mapping: If names don't match
        CreateMap<User, UserDto>()
            .ForMember(dest => dest.FullName,
                       opt => opt.MapFrom(src => $"{src.FirstName} {src.LastName}"));
    }
}
Copied!

Registration and Injection

In Program.cs, we register the service, indicating a type from the assembly where the profiles are located.

builder.Services.AddAutoMapper(
    cfg => cfg.LicenseKey = "<license-key>",
    typeof(MappingProfile));
Copied!

Since AutoMapper 13, AddAutoMapper is part of the main AutoMapper package. The old AutoMapper.Extensions.Microsoft.DependencyInjection package is discontinued. AutoMapper 15 requires reviewing its license and configuring a key; you can also discover it via the AUTOMAPPER_LICENSE_KEY environment variable.

Usage

We inject IMapper into our service or controller.

public class ProductService
{
    private readonly IMapper _mapper;

    public ProductService(IMapper mapper)
    {
        _mapper = mapper;
    }

    public ProductDto Get(int id)
    {
        var entity = _repo.Get(id);

        // Converts entity to DTO
        return _mapper.Map<ProductDto>(entity);
    }
}
Copied!

Mapster

In recent years, Mapster has gained popularity as an alternative with a simple API and code generation options.

Mapster can adapt objects at runtime and also offers compile-time code generation. If performance matters, it’s better to measure the real-world scenario rather than choosing based solely on a generic benchmark.

How it works

Mapster bets on convention over configuration. Often you don’t need to configure anything.

Installation

dotnet add package Mapster
Copied!

Direct Usage

You don’t need to inject anything if you don’t want to. Mapster adds extension methods to all your objects.

using Mapster;

public ProductDto Get(int id)
{
    var entity = _repo.Get(id);

    // Extension method .Adapt<T>()
    var dto = entity.Adapt<ProductDto>();

    return dto;
}
Copied!

Global Configuration

If you need custom mappings, you can configure them at application startup:

TypeAdapterConfig<User, UserDto>
    .NewConfig()
    .Map(dest => dest.FullName, src => src.FirstName + " " + src.LastName);
Copied!

AutoMapper and Mapster

FeatureAutoMapperMapster
Common ConfigurationProfiles and IMapperConventions, global configuration, or generated code
UsageIMapper injectionExtension methods like Adapt or configured services
Query ProjectionProjectToProjectToType
LicenseRequires reviewing license from version 15MIT

Manual Mapping

We can also not use any library and write explicit mapping methods.

Writing your own .ToDto() extension methods is repetitive, but it has clear advantages:

  1. Predictable Performance: Direct assignment avoids the mapper’s overhead.
  2. References: You can right-click -> “Find All References” on a property and know exactly where it’s being used. With AutoMapper, that relationship is hidden from the IDE.
  3. Debugging: If the mapping fails, you set a breakpoint and see it.
// Manual mapping with extension methods
public static class ProductMappers
{
    public static ProductDto ToDto(this Product entity)
    {
        return new ProductDto(entity.Id, entity.Name, entity.Price);
    }
}

// Usage
return entity.ToDto();
Copied!