According to https://automapper.org/, AutoMapper is:

A convention-based object-object mapper.

Or put another way, AutoMapper helps you get rid of code scattered through your application where you would map one object to another, and instead, configure it once, in one place.

Why Use AutoMapper?

If you've ever written the following type of code in one of your controller methods where you're mapping one object to a different object, and especially if you've ever written the same code in a different method, then there's a good chance that AutoMapper is for you.

[HttpGet("{id}")]
public IActionResult Get(int id)
{
    var playersDto = _footballRepository.GetPlayers(teamId).Select(player => {

        player.PreviousTeams.Insert(0, player.CurrentTeam);
        
        return new PlayerDto {
            Id = player.Id,
            Name = player.FirstName + " " + player.LastName,
            AllTeamsIncludingCurrent = player.PreviousTeams
        };
    });

    var teamDto = new TeamDto {
        Id = 1,
        Name = "Manchester United",
        Players = playersDto
    };

    return Ok(teamDto);
}

The above code could be used when we try to map from a list of Player entities, from EF Core for example, to a list of data transfer object (DTO), here called PlayerDto. Here is the Player object:

public class Player
{
    [Key]
    [Required]
    public int Id { get; set; }

    [Required]
    [MaxLength(100)]
    public string FirstName { get; set; }
    
    [Required]
    [MaxLength(100)]
    public string LastName { get; set; }

    [Required]
    public Team CurrentTeam { get; set; }

    public List<Team> PreviousTeams { get; set; }

}

And here is the PlayerDto object:

public class PlayerDto
{
    public int Id { get; set; }

    public string Name { get; set; }

    public List<Team> AllTeamsIncludingCurrent { get; set; }
}

We don't want to send unnecessary data across the wire, so AutoMapper is perfect for what we need to map one object to a different one. But as with the Get method above, we don't want to have that mapping code in our methods, especially as we may have the same code scattered all over our application, as we would then have to make sure that if we update it in one location that every other location is updated the same way.

Enter AutoMapper

In ASP.NET Core we can install AutoMapper using the following command:

dotnet add package AutoMapper --version 7.0.1

We can then setup our object mappings in the Startup.cs class in the Configure method like so:

AutoMapper.Mapper.Initialize(cfg =>
{
    cfg.CreateMap<Player, PlayerDto>()
        .ForMember(dest => dest.Name, opt => opt.MapFrom(src => $"{src.FirstName} {src.LastName}"))
        .ForMember(dest => dest.AllTeamsIncludingCurrent, opt => opt.MapFrom(src => src.PreviousTeams.Append(src.CurrentTeam)));
});

And then whenever we need that mapping we can use the following code which keeps our controllers clean, and means that any changes can be handled in one place:

var playerDto = Mapper.Map<List<PlayerDto>>(players);

So our Get method from above now looks like this:

[HttpGet("{id}")]
public IActionResult Get(int id)
{
    var players = _footballRepository.GetPlayers(id);
    var playersDto = Mapper.Map<List<PlayerDto>>(players);

    var teamDto = new TeamDto {
        Id = 1,
        Name = "Manchester United",
        Players = playersDto
    };

    return Ok(teamDto);
}

Summary

As you can see, this looks a lot cleaner and has the added benfits that if we want to map the same objects from a different method, we just use the same call to Mapper.Map<List<PlayerDto>>(players);