How to use AutoMapper in ASP.NET Core

By FoxLearn 2/21/2025 7:03:13 AM   20
In this guide, we will walk through how to integrate and use AutoMapper in an ASP.NET Core application.

What is AutoMapper?

AutoMapper is a powerful library used for object-to-object mapping, enabling automatic conversion between objects, which is particularly helpful for mapping complex objects (like Data Transfer Objects, or DTOs) to domain models, and vice versa. It eliminates the need for repetitive property mapping and helps keep your code cleaner and easier to maintain.

Why Use AutoMapper?

  • Reduces Code: Instead of manually mapping properties, AutoMapper takes care of property mapping automatically.
  • Improves Maintainability: By centralizing the mapping configuration, you only need to modify the logic in one place when changes are required.
  • Increases Productivity: AutoMapper speeds up development by reducing the amount of manual mapping code.
  • Standardizes Mapping: It ensures consistent and error-free mappings between objects.

How to Use AutoMapper in ASP.NET Core?

Step 1. Install AutoMapper

First, install AutoMapper and its integration with Dependency Injection by running the following commands in the NuGet Package Manager or the Package Manager Console:

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

Step 2. Create Models and DTOs

Define the models (e.g., Product) and the corresponding DTOs (e.g., ProductDTO).

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
    public int Stock { get; set; }
}

public class ProductDTO
{
    public string Name { get; set; }
    public decimal Price { get; set; }
}

Step 3. Create an AutoMapper Profile

Define the mapping configuration between the Product and ProductDTO objects in a MappingProfile class.

using AutoMapper;

public class MappingProfile : Profile
{
    public MappingProfile()
    {
        CreateMap<Product, ProductDTO>();
        CreateMap<ProductDTO, Product>();
    }
}

Step 4. Register AutoMapper in Program.cs

Register AutoMapper in the ConfigureServices() method to enable dependency injection and automatic mapping configuration.

using AutoMapper;

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();
    services.AddAutoMapper(typeof(Program));  // Register AutoMapper
}

Step 5. Use AutoMapper in a Controller

Here's how AutoMapper can be used in a ProductController to map between Product and ProductDTO objects.

[ApiController]
[Route("api/[controller]")]
public class ProductController : ControllerBase
{
    private readonly IMapper _mapper;

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

    [HttpPost]
    public IActionResult CreateProduct([FromBody] ProductDTO productDto)
    {
        var product = _mapper.Map<Product>(productDto);
        // Save the product entity to the database
        return Ok(product);
    }

    [HttpGet("{id}")]
    public IActionResult GetProduct(int id)
    {
        // Retrieve the product entity from the database
        var product = new Product { Id = id, Name = "Sample Product", Price = 100, Stock = 50 };

        var productDto = _mapper.Map<ProductDTO>(product);
        return Ok(productDto);
    }
}

Example Output

CreateProduct Request (Input: ProductDTO)

{
    "Name": "Laptop",
    "Price": 999.99
}

CreateProduct Response (Output: Product)

{
    "Id": 1,
    "Name": "Laptop",
    "Price": 999.99,
    "Stock": 50
}

GetProduct Request (GET /api/product/1)

{
    "Id": 1,
    "Name": "Laptop",
    "Price": 999.99
}

Mapping with Custom Logic

Sometimes, you may need to apply custom logic during the mapping process.

For example, you might need to format a field or compute a value.

Define Models and DTOs

public class Customer
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public DateTime BirthDate { get; set; }
}

public class CustomerDTO
{
    public string FullName { get; set; }
    public int Age { get; set; }
}

Create a Mapping Profile with Custom Logic

using AutoMapper;

public class CustomerProfile : Profile
{
    public CustomerProfile()
    {
        CreateMap<Customer, CustomerDTO>()
            .ForMember(dest => dest.FullName, opt => opt.MapFrom(src => $"{src.FirstName} {src.LastName}"))
            .ForMember(dest => dest.Age, opt => opt.MapFrom(src => CalculateAge(src.BirthDate)));
    }

    private int CalculateAge(DateTime birthDate)
    {
        var today = DateTime.Today;
        var age = today.Year - birthDate.Year;
        if (birthDate.Date > today.AddYears(-age))
        {
            age--;
        }
        return age;
    }
}

Use AutoMapper in a Controller

[HttpPost]
public IActionResult CreateCustomer([FromBody] Customer customer)
{
    var customerDto = _mapper.Map<CustomerDTO>(customer);
    return Ok(customerDto);
}

Sample Response

CreateCustomer Request (Input: Customer)

{
    "FirstName": "Jane",
    "LastName": "Doe",
    "BirthDate": "1990-05-15"
}

CreateCustomer Response (Output: CustomerDTO)

{
    "FullName": "Jane Doe",
    "Age": 34
}

Flattening Complex Objects

Flattening complex objects allows you to simplify nested structures into a flat one.

Define Models and DTOs

public class Order
{
    public int OrderId { get; set; }
    public DateTime OrderDate { get; set; }
    public Customer Customer { get; set; }
    public List<OrderDetail> OrderDetails { get; set; }
}

public class OrderDetail
{
    public int ProductId { get; set; }
    public string ProductName { get; set; }
    public int Quantity { get; set; }
    public decimal Price { get; set; }
}

public class OrderDto
{
    public int OrderId { get; set; }
    public DateTime OrderDate { get; set; }
    public string CustomerName { get; set; }
    public string CustomerEmail { get; set; }
    public List<OrderDetailDto> OrderDetails { get; set; }
}

public class OrderDetailDto
{
    public int ProductId { get; set; }
    public string ProductName { get; set; }
    public int Quantity { get; set; }
    public decimal Price { get; set; }
}

Create a Mapping Profile

using AutoMapper;

public class OrderProfile : Profile
{
    public OrderProfile()
    {
        CreateMap<Order, OrderDto>()
            .ForMember(dest => dest.CustomerName, opt => opt.MapFrom(src => src.Customer.Name))
            .ForMember(dest => dest.CustomerEmail, opt => opt.MapFrom(src => src.Customer.Email));
        CreateMap<OrderDetail, OrderDetailDto>();
    }
}

Use AutoMapper in a Controller

[HttpPost]
public IActionResult CreateOrder([FromBody] Order order)
{
    var orderDto = _mapper.Map<OrderDto>(order);
    return Ok(orderDto);
}

Sample Output

CreateOrder Request (Input: Order)

{
    "OrderId": 1001,
    "OrderDate": "2024-05-15T10:30:00",
    "Customer": {
        "Name": "John Doe",
        "Email": "[email protected]"
    },
    "OrderDetails": [
        {
            "ProductId": 1,
            "ProductName": "Smartphone",
            "Quantity": 2,
            "Price": 500.00
        }
    ]
}

CreateOrder Response (Output: OrderDto)

{
    "OrderId": 1001,
    "OrderDate": "2024-05-15T10:30:00",
    "CustomerName": "John Doe",
    "CustomerEmail": "[email protected]",
    "OrderDetails": [
        {
            "ProductId": 1,
            "ProductName": "Smartphone",
            "Quantity": 2,
            "Price": 500.00
        }
    ]
}

AutoMapper is an incredibly useful tool for simplifying object mapping and reducing boilerplate code, making your development process much more efficient and maintainable.