What is AutoMapper? - The Definitive Guide

A thumbnail showing C# code. Everything you need to know about C# AutoMapper.

As a C# developer, you probably now how boring it is to map between objects.

You end up with repetitive code like:

csharp
AddressDTO dto = new
{
    FirstName = address.FirstName,
    LastName = address.LastName,
    Street1 = address.Street1,
    //... and so on..
}

That's where AutoMapper comes in.

AutoMapper is a library that helps with mapping objects in .NET. The manual process of mapping is tedious. Instead, with AutoMapper we can automatically map between our objects. We configure the mapping once and then reuse it anywhere in the code.

So instead of manually mapping the Address from our example above, we can use AutoMapper:

csharp
 var dto = AutoMapper.Mapper.Map<AddressDTO>(address);

Why do we need AutoMapper?

AutoMapper helps us concentrate on important parts of our code.

It delegates the boring task of mapping.

It does the job. And it's been doing so for over 10 years.

Also, we don't have to write hundreds of unit tests to verify the mapping. AutoMapper does it for us.

Message explaining the purpose of AutoMapper.

How to set up AutoMapper?

To set up AutoMapper in an ASP.NET Core project, follow these steps:

Step 1: Install AutoMapper

AutoMapper comes as a NuGet package. To install it, run the Install-Package command in the package manager console:

Install-Package AutoMapper
Install-Package AutoMapper.Extensions.Microsoft.DependencyInjection

Step 2: Define Profiles

Define which objects map to each other using a Profile.

Profile is a class that we can use to define mapping configuration between our objects:

csharp
public class OrderProfile : Profile
{
	public OrderProfile()
	{
		CreateMap<Address, AddressDTO>();
		CreateMap<Order, OrderDTO>();
		// ... Add more mappings.
	}
}

Our custom OrderProfile class inherits from AutoMapper's Profile.

Step 3: Register Dependency

Go to your Startup.cs file and locate the ConfigureServices method.

We need to register the AutoMapper dependency with our service collection:

csharp
services.AddAutoMapper(typeof(Startup));

AddAutoMapper extension method registers all mapping profiles in an assembly.

Step 4: Inject AutoMapper

Use the injected AutoMapper instance in our controller:

csharp
public class OrderController : Controller
{

	private readonly IMapper _mapper;
	public OrderController(IMapper mapper)
	{
		_mapper = mapper;
    }
    public IActionResult Address()
	{
        var address = GetAddress();
        return _mapper.Map<AddressDTO>(address);
	}
}

We use the Map method to map from the domain object to view data transfer objects (DTO):

csharp
var addressDto = _mapper.Map<AddressDTO>(address);

In the angle brackets, we specify the destination object type we want to map to.

  • address is the input object of type Address.
  • addressDto is the output object of type AddressDTO.

Features

AutoMapper is a simple library with a lot of power.

Here are the top features that you should know about:

LINQ Query Optimization

If you are pulling data from a database, you need to be careful with performance.

To make our queries quick, we need to pull just what we need. No more.

AutoMapper supports LINQ using the QueryableExtensions to build projections.

For example, if we are using Entity Framework and LINQ, we have access to the IQueryable interface that we can use with AutoMapper.

AutoMapper's ProjectTo extension method allows us to extract just what we need from the query:

csharp
context.Orders.Where(o => o.Id == orderId)
             .ProjectTo<OrderDTO>().ToList();

Here, our query will select fields that OrderDTO needs, and ignore everything else that Order might have.

Use ProjectTo to improve the performance of your Entity framework queries.

Conditional Mapping

AutoMapper's conditional mappings are useful when you want to use different mappings based on your custom logic.

For example, if you have IsAnonymous flag that shows that the user is an anonymous customer, you can specify a different mapping for the name.

csharp
CreateMap<Customer, CustomerDTO>()
    .ForMember(dest => dest.Name, opt => opt.Condition(src => !src.IsAnonymous)));

Or if you have different mappings based on string length:

csharp
CreateMap<Customer, CustomerDTO>()
    .ForMember(dest => dest.Name, opt => opt.Condition(src => src.Length < 3)));

Before/After actions

Sometimes you might need to change the data before or after a map happens.

AutoMapper allows you to hook into the map process and change properties as needed.

For example, if we want to check the IsActive flag before mapping, we can do it:

csharp
CreateMap<Address>().BeforeMap(src => src.IsActive = false);

Who created AutoMapper?

Jimmy Bogard created AutoMapper in 2009.

Jimmy has been working as a software developer for over 15 years.

He's a Microsoft MVP in ASP.NET, a popular open-source contributor, and an author of C# books.

He also created MediatR, a mediator pattern implementation for C#. The project has over 7000 starts on GitHub.

Jimmy Bogard's GitHub page.

Open source

AutoMapper is open source and available on GitHub.

It's released under MIT license so you can use it freely for both open source and commercial projects.

How does AutoMapper work?

If we look at AutoMapper's source code, we find it uses a combination of Reflection.Emit and expression tree compilation.

Reflection is process of inspecting the metadata and compiled code at runtime.

The metadata contains information on object’s type and properties which AutoMapper uses to figure out how to map between objects.

ToStringMap AutoMapper code example.
Example of AutoMapper C# code using reflection.

How does AutoMapper know which properties to map?

AutoMapper maps based on source and destination property names.

If you have a different property name between types, you need to specify the mapping:

csharp
CreateMap<Address, Order>()
  .ForMember(dest => dest.AddressId, opt => opt.Id);

This will change the destination property name from AddressId to Id.

When to use AutoMapper?

You probably don't need AutoMapper.

AutoMapper shines when you have thousands of properties to map.

This is a rare use case for most applications.

If you have only a few objects with properties, manually map them.

Writing a few extra lines of code is better than configuring AutoMapper.

Before you install AutoMapper, ask yourself:

  1. How many properties do I need to map?
  2. Is my codebase going to be affected if I add or remove mappings?
  3. How often are my properties going to change?
  4. How many custom mappings do I have?

If you have a large project with thousands of snowflake DTOs, AutoMapper will make your life easier.

If more than 10% of your mappings use Ignore's, Conditions, and MapFrom's, don't use AutoMapper. You'll just make your life harder because AutoMapper wasn't designed for complex custom-mapping scenarios.

Cons

As a developer, you must consider the cons of any tool before using it.

There's always been a heated debate in the .NET community about using AutoMapper.

Message from a person not liking AutoMapper.

Some love it, some hate it.

But I think AutoMapper's drawbacks don't come from the library itself, but from how it's used.

Misuse

I've seen many projects where developers used AutoMapper to solve wrong problems.

For example, they would add business logic to the conditional mapping.

This results in fragile mappings that are difficult to maintain.

AutoMapper's misuse.

Overuse

Developers often think that if you're using something like AutoMapper, you must use it all the time.

You can use it for 80% of the cases where you are mapping identical properties.

But for the other 20%, where it is not automatic, don't use it.

Manual mapping might be boring, but it makes intent easier to understand.

Other drawbacks

  • You may end up spending more time configuring AutoMapper than what I'd take to do the mapping by hand.
  • If you configure it incorrectly, it can throw ambiguous exceptions.
  • It's hard to debug.

Things to avoid

You should avoid:

  • Conditional Mappings
  • Using MapFrom for objects that can map automatically
  • Circular objects
  • Mapping from simple to complex objects
  • Using the static Mapper class. Use Dependency injection.

AutoMapper makes it harder to see what is happening when it is mapping things. This can be annoying, but it often depends on what you are using it for.

Who uses AutoMapper?

Some of the most popular projects that use AutoMapper are :

Besides open-source projects, many enterprise applications use AutoMapper.

AutoMapper is a very popular tool, it has over 200 million downloads.

AutoMapper's popularity showing downloads on NuGet.

AutoMapper Alternatives

The most popular AutoMapper alternatives are:

Mapster NuGet package as AutoMapper alternative.

Tools

Mapster and AgilieMapper are like AutoMapper.

They are both focused on mapping between POCO classes and DTOs.

On the other hand, MappingGenerator is a Visual Studio extension that allows developers to generate mapping code.

Using MappingGenerator is my favorite alternative to AutoMapper because it doesn't have any package dependencies.

Extension methods

Using static extension methods is an AutoMapper alternative that doesn't require any external tools.

Here's an example:

csharp
public static OrderDTO ToDTO(this Order source)
      => new OrderDTO
        {

        Id = source.Id,
        Total = source.Total

        });

In the code above, the purpose of extracting the mapping logic to the external method is to make it reusable.

AutoMapper extensions

AutoMapper has several extensions that enhance its functionality.

AutoMapper core team creates and maintain most of the extensions.

The most popular extensions include:

They are available through NuGet.

Go to their GitHub organization page to see all the extensions.

Dependency injection vs static class

Before version 4.2, AutoMapper relied on the static API.

The static API had number of issues, mostly related to AutoMapper scattered all around the code base.

Even Jimmy Bogard, the author of AutoMapper admits it:

Blog post from Jimmy Bogard talking about static classes.

Instead, AutoMapper now solely uses the IMapper interface.

The interface allows you to use dependency injection and keeps your code cleaner.

If you stumble upon an older implementation of AutoMapper, I suggest that you replace it with this newer implementation.

AutoMapper Performance

AutoMapper affects the performance of your application.

It takes time to load during project startup and when you map between objects.

But in most cases, this should not be an issue because most applications don't have objects with thousands of properties.

You should measure performance implications to make sure there is no issue.

Conclusion

AutoMapper is a library that takes the pain out of mapping properties.

It converts domain objects into DTOs, which makes the codebase more maintainable.

Dependency injection with ASP.NET Core makes it easy to use and test.

It has a lot of features that make it easy to optimize your queries and improve performance. You can use conditional mapping to specify different mappings based on custom logic, and before/after actions to change the data before or after a map occurs.

That said, AutoMapper isn't perfect - misuse or overuse can produce confusing results and hard-to-debug exceptions.

If you're new to using this powerful helper library, take time to learn how best to use it before diving headfirst into creating mappings.

Use AutoMapper with caution. Many times, you can avoid AutoMapper altogether.

FAQ

What's the benefit of domains in ASP.NET applications?

The main benefits of using domains is separation of concerns.

Entities shouldn't know about DTOs.

That way, we can change the DTOs without touching the entities and vice versa.

Another benefits of having separate domains is added security.

Andrew Lock discussed how we can use AutoMapper to protect against mass assignment attacks.

Mass assignment is an attack where an attacker sets values on a website that were not intended to change. This can happen when websites use model binding, which is a way to map input to a model.

If we separate the presentation layer from the model, we can simply map and validate data using AutoMapper.

The book Pro ASP.NET Web API Security also discusses the use of separate domains and AutoMapper to protect against the mass assignment attack.

How to skip mappings for some properties?

To skip mappings for some properties, we can use the DoNotValidate method when we configure the mapping profile:

csharp
cfg.CreateMap<Source, Dest>()
    .ForSourceMember(source => source.Date, opt => opt.DoNotValidate());

Calling DoNotValidate() ignores member for configuration validation and skips it during mapping.

How to substitute null values?

To substitute null values using AutoMapper use the NullSubstitute method:

csharp
CreateMap<Source, Dest>()
      .ForMember(destination => destination.Value, opt => opt.NullSubstitute("Default Value")));
Published on