How to Use Automapper in ASP.NET Core Web API

How to Use Automapper in ASP.NET Core Web API

In this article, I will discuss How to Use Automapper in ASP.NET Core Web API Application with Examples. Please read our previous article discussing Model Binding in ASP.NET Core Web API with Examples.

Automapper in ASP.NET Core Web API

Automapper in ASP.NET Core is used to simplify the task of mapping one object to another in your application. This is useful in scenarios where you have complex data models, and you need to transfer data between types that have similar structures but are not identical. Automapper can help reduce the amount of manual mapping code you need to write, thereby making your codebase cleaner and more maintainable.

When developing an application, it’s common to have different layers where each layer has its own representation of data. For example, the domain layer might have entities that closely represent the database schema, while the application layer might use DTOs that are specific to the needs of the client, such as the UI. Manually converting between these objects can be tedious and error-prone, especially as the application grows and the number of fields increases.

AutoMapper helps automate the mapping between objects, reducing the amount of code developers need to write. Instead of manually assigning each property from one object to another, AutoMapper uses conventions to map properties with the same name and compatible types automatically. Developers can also configure custom mapping rules for more complex scenarios where properties might not match exactly or require conversion.

Example to Understand Automapper in ASP.NET Core Web API:

Let us see an Example to Understand How to Use Automapper in the ASP.NET Core Web API Application. First, create a new ASP.NET Core Web API Application with the name AutomapperDemo.

Define Domain Models and DTOs:

Create the following Employee domain Model and EmployeeDTO.

Employee Model:

Create a class file named Employee.cs, and then copy and paste the following code. This is going to be our model class, which will be used to interact with the database. This model includes all the basic as well as sensitive information, including Salary and SocialSecurityNumber.

namespace AutomapperDemo.Models
{
    public class Employee
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Email { get; set; }
        public string Gender { get; set; }
        public int Age { get; set; }
        // Sensitive Information
        public string SocialSecurityNumber { get; set; }
        public decimal Salary { get; set; }
    }
}
EmployeeDTO:

Create a class file named EmployeeDTO.cs and then copy and paste the following code. This is going to be our DTO, which will be used to communicate with the client. This DTO includes only basic information about the Employee without including Salary and SocialSecurityNumber. So, basically, we don’t want to expose the Sensitive information to the client.

namespace AutomapperDemo.Models
{
    public class EmployeeDTO
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Email { get; set; }
        public string Gender { get; set; }
        public int Age { get; set; }
    }
}
Creating the Employee Controller:

Next, create an API Empty Controller named Employee Controller as follows. The GetEmployees action method is used to return all the Employees using the EmployeeDTO, and the AddEmployee method is used to add a new Employee, and this method also takes the EmployeeDTO as a parameter.

using AutomapperDemo.Models;
using Microsoft.AspNetCore.Mvc;

namespace AutomapperDemo.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class EmployeeController : ControllerBase
    {
        private List<Employee> listEmployees = new List<Employee>()
        {
            new Employee(){ Id = 1, Name = "Anurag", Age = 28, Salary=1000, Gender = "Male", Email = "Anurag@Example.com", SocialSecurityNumber="1234@Anurag" },
            new Employee(){ Id = 2, Name = "Pranaya", Age = 30, Salary=2000, Gender = "Male", Email = "Pranaya@Example.com", SocialSecurityNumber="4567@Pranaya" },
        };

        [HttpGet]
        public ActionResult<List<EmployeeDTO>> GetEmployees()
        {
            //We cannot expose the Sensitive Information
            //We are going to return the Employees to the Client using EmployeeDTO

            //So, manually creating instance and mapping the employees from Employee to EmployeeDTO
            List<EmployeeDTO> employees = new List<EmployeeDTO>();

            foreach (var employee in listEmployees)
            {
                EmployeeDTO emp = new EmployeeDTO()
                {
                    //Setting the Id, Name, Age, Gender, and Email
                    Id = employee.Id,
                    Name = employee.Name,
                    Age = employee.Age,
                    Gender = employee.Gender,
                    Email = employee.Email,
                };
                employees.Add(emp);
            }
            return Ok(employees);
        }

        [HttpPost]
        public ActionResult<EmployeeDTO> AddEmployee(EmployeeDTO employee)
        {
            if (employee != null && employee.Id == 0)
            {
                //Create an Instance of Employee Object and Populate the Properties manually
                Employee emp = new Employee()
                {
                    Id = listEmployees.Count + 1,
                    Name = employee.Name,
                    Age = employee.Age,
                    Gender = employee.Gender,
                    Email = employee.Email,
                    Salary = 3000,
                    SocialSecurityNumber = $"2356@{employee.Name}"
                };
                
                //Adding Employee Object into the Database
                listEmployees.Add(emp);

                //Setting the Employee ID in EmployeeDTO
                employee.Id = emp.Id;

                //Returning the EmployeeDTO
                return Ok(employee);
            }

            //If the Incoming Data in not Valid Return Bad Request
            return BadRequest();
        }
    }
}

As you can see in the above example, we are manually mapping the Employee to EmployeeDTO in the GetEmployees method and EmployeeDTO to Employee in the AddEmployee method. If you run the application, you will get the output as expected, as shown in the below image:

API 1: Get all Employees

URL: api/employee

Method: GET

Example to Understand Automapper in ASP.NET Core Web API

API 2: Add a New Employee

URL: api/employee

Method: POST

Request Body

{
  "name": "Priyanka",
  "email": "Priyanka@Example.com",
  "gender": "Female",
  "age": 28
}

Example to Understand Automapper in ASP.NET Core Web API

The application is working as expected. But tomorrow, what will you do if the data, i.e., the properties in the Employee and EmployeeDTO classes, are increased? Then, you must write the data mapping code for each property from the source class to the destination class. That means the code mapping is repeated between the source and the destination. Again, if the same mapping is at different places, then you also need to make the changes at different places, which is time-consuming and error-prone. This is where the Automapper will come into the picture.

Automapper in ASP.NET Core Web API

Automapper is a popular object-to-object mapping library that simplifies the process of transferring data between different objects. In the context of an ASP.NET Core Web API, Automapper can significantly reduce the amount of code needed to map data models to DTOs (Data Transfer Objects) and vice versa. This is useful in the layer of your application where you’re dealing with transferring data between your internal business logic models and the models you expose to the external world via your API.

How to Use AutoMapper in ASP.NET Core:
  • Install AutoMapper: First, you need to add AutoMapper to your ASP.NET Core project. This is typically done via NuGet by installing the AutoMapper package.
  • Create Mapping Profiles: Create mapping profiles by inheriting from the Profile class provided by AutoMapper. In this class, we need to define our mapping configurations, such as specifying source and destination types and any custom mapping rules.
  • Register AutoMapper: Register AutoMapper and your mapping profiles with ASP.NET Core’s Dependency Injection container in the Program.cs file.
  • Inject IMapper: Use dependency injection to inject IMapper into your controllers or services where you need to perform object mapping.
  • Map Objects: Use the IMapper.Map<TSource, TDestination> method to map between objects.
Installing AutoMapper in ASP.NET Core Web API

First, you need to add the AutoMapper Package in ASP.NET Core to your project. This can be done via NuGet Package Manager or the Package Manager Console. Open NuGet Package Manager for Solution, and then search for AutoMapper, select the package, select the Project, select the latest stable version, and click on the Install button as shown in the below image:

Installing AutoMapper in ASP.NET Core Web API

This should install the Automapper package, and you can verify the same within the Packages folder, as shown in the below image.

Installing AutoMapper in ASP.NET Core Web API

Ultimately, you can also install the Package using Package Manager Console or .NET Core CLI as follows:

Package Manager Console Command: Install-Package AutoMapper

.NET CLI Command: dotnet add package AutoMapper

Automapper Configuration

After installing the Automapper package, then we need to configure Automapper in our application. This involves creating mapping profiles and registering Automapper in the ASP.NET Core dependency injection container.

Create a Mapping Profile

A profile in AutoMapper is a class that extends Profile. This class is where you define the mappings between source and destination types. Within a profile, you use the CreateMap<TSource, TDestination>() method to specify how two types should be mapped to each other.

In the mapping configuration, you can specify more than just a straightforward property-to-property mapping. AutoMapper allows for custom value transformations, conditional mappings, and more complex scenarios. So, create a class file named MyMappingProfile.cs and then copy and paste the following code:

using AutoMapper;

namespace AutomapperDemo.Models
{
    public class MyMappingProfile : Profile
    {
        public MyMappingProfile()
        {
            //Configure the Mappings

            //Mapping Employee to EmployeeDTO
            //Source: Employee and Destination: EmployeeDTO
            CreateMap<Employee, EmployeeDTO>();

            //Mapping EmployeeDTO to Employee
            //Source: EmployeeDTO and Destination: Employee
            CreateMap<EmployeeDTO, Employee>();
        }
    }
}
Register AutoMapper in Program.cs

Register AutoMapper and your profiles with the dependency injection container in Program.cs. So, please add the following statement within the Program class. This configuration tells AutoMapper to scan the assembly (or assemblies) for classes that inherit from Profile and automatically register them.

builder.Services.AddAutoMapper(typeof(Program).Assembly);

Understanding the above statement:
  • AddAutoMapper(): This is an extension method provided by the AutoMapper package. It is designed to simplify the process of registering AutoMapper with the ASP.NET Core DI container.
  • typeof(Program).Assembly: The typeof(Program).Assembly expression is used to specify the assembly to scan for AutoMapper profiles. typeof(Program) gets a Type object representing the Program class, which is the entry point of your ASP.NET Core application. .Assembly then accesses the assembly that contains this type. In essence, this tells AutoMapper to look in the same assembly as where the Program class is located to find any classes that inherit from AutoMapper’s Profile class. These profiles contain the configurations for mapping between different object types.
What Happens Internally?

When you call AddAutoMapper and pass it the assembly to scan, AutoMapper will look through those assemblies for any class that extends the Profile class. For each found profile, it will register the mappings defined within that profile with its mapping engine. This process ensures that all your configured mappings are available to the application, and it allows you to use the IMapper interface to perform mappings wherever needed.

Use AutoMapper in ASP.NET Core Web API Controller:

AutoMapper is typically used by injecting IMapper into your classes (e.g., controllers, services). This interface provides the mapping functionality that can be used to map objects. To map an object from one type to another, you use the Map<TDestination>(object source) method of the IMapper instance. AutoMapper uses the configuration defined in profiles to perform the mapping. So, modify the Employee Controller as follows:

using AutoMapper;
using AutomapperDemo.Models;
using Microsoft.AspNetCore.Mvc;

namespace AutomapperDemo.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class EmployeeController : ControllerBase
    {
        //Create a variable to holder mapper instance
        private readonly IMapper _mapper;

        //Framework will inject the instance using Constructor
        public EmployeeController(IMapper mapper)
        {
            //Initialize the variable with the injected mapper instance
            _mapper = mapper;
        }

        private List<Employee> listEmployees = new List<Employee>()
        {
            new Employee(){ Id = 1, Name = "Anurag", Age = 28, Salary=1000, Gender = "Male", Email = "Anurag@Example.com", SocialSecurityNumber="1234@Anurag" },
            new Employee(){ Id = 2, Name = "Pranaya", Age = 30, Salary=2000, Gender = "Male", Email = "Pranaya@Example.com", SocialSecurityNumber="4567@Pranaya" },
        };

        [HttpGet]
        public ActionResult<List<EmployeeDTO>> GetEmployees()
        {
            // Use AutoMapper to map from Employee to EmployeeDTO
            List<EmployeeDTO> employees = _mapper.Map<List<EmployeeDTO>>(listEmployees);

            return Ok(employees);
        }

        [HttpPost]
        public ActionResult<EmployeeDTO> AddEmployee(EmployeeDTO employee)
        {
            if (employee != null && employee.Id == 0)
            {
                // Use AutoMapper to map from EmployeeDTO to Employee
                Employee emp = _mapper.Map<Employee>(employee);

                //Mannually Set the Properties which are not aviable in DTO
                emp.Id = listEmployees.Count + 1;
                emp.Salary = 3000;
                emp.SocialSecurityNumber = $"2356@{emp.Name}";
               
                //Adding Employee Object into the Database
                listEmployees.Add(emp);

                //Setting the Employee ID in EmployeeDTO
                employee.Id = emp.Id;

                //Returning the EmployeeDTO
                return Ok(employee);
            }

            //If the Incoming Data in not Valid Return Bad Requestr
            return BadRequest();
        }
    }
}

As you can see in the above example, we are using Automapper to map the Employee to EmployeeDTO in the GetEmployees method and EmployeeDTO to Employee in the AddEmployee method. Now, if you run the application, you will get the same output as expected, as shown in the below image:

API 1: Get all Employees

URL: api/employee

Method: GET

Automapper in ASP.NET Core Web API

API 2: Add a New Employee

URL: api/employee

Method: POST

Request Body

{
  "name": "Priyanka",
  "email": "Priyanka@Example.com",
  "gender": "Female",
  "age": 28
}

Use AutoMapper in ASP.NET Core Web API Controller

What will happen if the Source and Destination Property Names are Different?

Let us understand this with an example. Let us change the property names of the EmployeeDTO class. Change the Name property to FullName and Email property to EmailId. So, modify the EmployeeDTO class as follows.

namespace AutomapperDemo.Models
{
    public class EmployeeDTO
    {
        public int Id { get; set; }
        public string FullName { get; set; }
        public string EmailId { get; set; }
        public string Gender { get; set; }
        public int Age { get; set; }
    }
}

With the above changes in place, now run the application, and try to access all the Employees using /api/employee using GET request, and you will see the following data.

What will happen if the Source and Destination Property Names are Different?

As you can see in the above image, the Full Name and Email ID are empty, meaning these two properties are not mapped from the Source to the Destination types. So, the point that you need to remember is when the property names are different in Source and Destination types, then by default, Automapper will not map those properties from the source object to the destination object.

How Do We Map Properties When Property Names are Different Using AutoMapper?

If the Property names differ in Source and Destination types, then you need to map such properties in AutoMapper using the ForMember option. So, to Map the Name property of the Source Object with the FullName property of the Destination Object and the Email property of the Source Object with the EmailId property of the Destination Object, we need to provide these mapping configurations in the Automapper Profile explicitly.

So, modify the MyMappingProfile class file to provide such property mapping configurations. In our upcoming article, we will discuss the ForMember and MapForm options in detail.

using AutoMapper;

namespace AutomapperDemo.Models
{
    public class MyMappingProfile : Profile
    {
        public MyMappingProfile()
        {
            //Configure the Mappings

            //Mapping Employee to EmployeeDTO
            //Source: Employee and Destination: EmployeeDTO
            CreateMap<Employee, EmployeeDTO>()
                //Provide Mapping Configuration of FullName and Name Property
                .ForMember(dest => dest.FullName, act => act.MapFrom(src => src.Name))

                //Provide Mapping Configuration of EmailId and Email Property
                .ForMember(dest => dest.EmailId, act => act.MapFrom(src => src.Email));

            //Mapping EmployeeDTO to Employee
            //Source: EmployeeDTO and Destination: Employee
            CreateMap<EmployeeDTO, Employee>()
                //Provide Mapping Configuration of Name and FullName Property
                .ForMember(dest => dest.Name, act => act.MapFrom(src => src.FullName))

                //Provide Mapping Configuration of Email and EmailId Property
                .ForMember(dest => dest.Email, act => act.MapFrom(src => src.EmailId));
        }
    }
}

With these changes in place, now run the application and access the endpoints, and you should get the output as expected as follows:

API 1: Get all Employees

URL: api/employee

Method: GET

How Do We Map Properties When Property Names are Different Using AutoMapper?

API 2: Add a New Employee

URL: api/employee

Method: POST

Request Body

{
  "fullName": "Priyanka",
  "emailId": "Priyanka@Example.com",
  "gender": "Female",
  "age": 28
}

How to Use AutoMapper in ASP.NET Core Web API with Examples

Key Features of Automapper:
  • Convention-Based Mapping: Automapper relies on conventions to automatically map properties between objects. For instance, if two objects have properties with the same name and compatible types, Automapper can automatically map these without any configuration.
  • Custom Mapping: For cases where properties do not match directly or require complex transformations, you can define custom mapping rules. Automapper allows developers to define custom rules for how properties are mapped, including conditions, transformations, and more complex scenarios.
  • Flattening: AutoMapper can automatically flatten complex object models into simpler, flattened DTOs. This is useful when the client needs a simpler model than the one used internally.
  • Configuration Validation: AutoMapper provides built-in validation features to validate mapping configurations at startup, ensuring that all mappings are valid and can be executed without error, which helps in catching mapping issues early in the development cycle.
  • Projection: AutoMapper can project data directly from data source queries (e.g., LINQ queries) to DTOs, optimizing data retrieval and transformation performance, especially useful with Entity Framework Core.
  • Dependency Injection Support: ASP.NET Core’s built-in dependency injection (DI) framework can be used to configure and inject AutoMapper, making it easy to use across the application.

In the next article, I will discuss Automapper Complex Mapping in ASP.NET Core Web API with Examples. In this article, I explain How to Use AutoMapper in ASP.NET Core Web API with Examples. I hope you enjoy this article, “AutoMapper in ASP.NET Core Web API.”

Leave a Reply

Your email address will not be published. Required fields are marked *