Getting Started With Mapster in ASP.NET Core

In this article, we’re going to learn how to use Mapster in ASP.NET Core applications.

First, we’ll learn what Mapster is and how we can install it inside the .NET Core application. Then, we are going to try different options for mapping data when using Mapster. After that, we’ll learn about Mapster functionalities for generating code and flattening objects inside our Web API project.

What is Mapster?

Mapster is a powerful library designed to map objects from one type to another effortlessly. It follows a convention-based approach that's easy to configure and use, sparing developers from writing repetitive and error-prone boilerplate code.

Installing Mapster To get started, let's install the Mapster NuGet package.

dotnet add package Mapster

With Mapster added to our project, we're ready to harness its capabilities.

Setting Up the Environment Let's begin by defining two classes to represent entities and one class for the DTO object.

public class Product
{
    public string? Name { get; set; }
    public string? Category { get; set; }
    public decimal Price { get; set; }
    public int StockQuantity { get; set; }
}

public class OrderItem
{
    public string? ProductName { get; set; }
    public int Quantity { get; set; }
}

public class OrderItemDto
{
    public string? ProductName { get; set; }
    public int Quantity { get; set; }
    public decimal TotalPrice { get; set; }
}

These classes will serve as the basis for our mapping examples. Now, let's create a simple method to generate sample data.

public static Product CreateProduct()
{
    return new Product()
    {
        Name = "Smartphone",
        Category = "Electronics",
        Price = 599.99m,
        StockQuantity = 100
    };
}

This method creates a sample Product object. Similarly, we'll create a method to generate a collection of OrderItem objects.

Basic Mapping With Mapster Let's now explore basic object mapping using Mapster without any additional configuration. We'll create a static class named MappingFunctions to implement our mapping functionalities.

public static class MappingFunctions
{
    private static readonly Product _product = DemoData.CreateProduct();

    public static OrderItemDto MapProductToOrderItemDto()
    {
        var orderItemDto = _product.Adapt<OrderItemDto>();
        orderItemDto.TotalPrice = _product.Price * _product.StockQuantity;
        return orderItemDto;
    }
}

In this class, we initialize a sample Product object. The MapProductToOrderItemDto() method maps a Product object to an OrderItemDto object and calculates the total price.

To consume this mapping, let's create a controller:

[Route("api/orders")]
[ApiController]
public class OrdersController : ControllerBase
{
    [HttpGet("new-order-item")]
    public IActionResult GetNewOrderItem()
    {
        var orderItem = MappingFunctions.MapProductToOrderItemDto();
        return Ok(orderItem);
    }
}

This controller exposes an endpoint to retrieve mapped data. When accessing the "new-order-item" route, it calls the MapProductToOrderItemDto() method and returns the mapped OrderItemDto object.

With these steps, we've successfully integrated Mapster into our ASP.NET Core application, enabling seamless object mapping within our Web API project.

Mapping to an Existing Object

Another approach to mapping involves mapping data to an existing object:

public static ProductDto MapProductToExistingDto()
{
    var productDto = new ProductDto();
    _product.Adapt(productDto);

    return productDto;
}

In this scenario, we first create a new PersonDto object. Then, we map data from the _person object to the existing personDto variable using the Adapt() method.

Let's integrate this mapping into our controller.

[HttpGet("existing-product")]
public IActionResult GetExistingProduct()
{
    var product = MappingFunctions.MapProductToExistingDto();

    return Ok(product);
}

Here, we introduce the GetExistingPerson() action with a new URI specified on the action.

Mapping Collections

Mapster library also facilitates mapping from Queryable in .NET, which can expedite the mapping process for data obtained from databases within the Queryable data type.

Let’s implement another method in our MappingFunctions class.

public static IQueryable<OrderItemDto> MapOrderItemQueryableToDtoQueryable()
{
    var orderItemsQueryable = _orderItems.AsQueryable();
    var orderItemDtos = orderItemsQueryable.Adapt<OrderItemDto>();

    return orderItemDtos;
}

In the MapPersonQueryableToDtoQueryable() method, we store data from the _people object into the peopleQueryable variable using the AsQueryable() method. Next, we use the Adapt() method from Mapster to map the data to the personDtos variable.

Again, let’s create a new endpoint in our controller to test the functionality.

[HttpGet]
public IActionResult GetOrderItemsQueryable()
{
    var orderItems = MappingFunctions.MapOrderItemQueryableToDtoQueryable();

    return Ok(orderItems);
}

Custom Mapping With Mapster

Now, let’s explore custom mapping functionalities to see the potential of the Mapster library.

To implement custom mapping logic, we need to add a custom Mapster configuration using the TypeAdapterConfig class.

First, let’s add a MapsterConfig static class with an extension method for Mapster configuration.

public static class MapsterConfig
{
    public static void RegisterMapsterConfiguration()
    {
    }
}

Then, we can use the RegisterMapsterConfiguration() extension method in our services within the Program class:

builder.Services.RegisterMapsterConfiguration();

Now, we’re ready to implement custom mapping with Mapster.

Mapping to Different Members

What if we have properties with different names inside our DTO classes? Mapster offers a solution for that.

Let’s add another DTO class, which we will use to present information for our OrderItem entity:

public class OrderItemShortInfoDto
{
    public string? ProductName { get; set; }
    public int Quantity { get; set; }
}

In our OrderItemShortInfoDto class, we have properties similar to the OrderItem entity.

After that, we add a new configuration to our RegisterMapsterConfiguration() extension method.

public static void RegisterMapsterConfiguration()
{
    TypeAdapterConfig<OrderItem, OrderItemShortInfoDto>
        .NewConfig()
        .Map(dest => dest.ProductName, src => src.ProductName)
        .Map(dest => dest.Quantity, src => src.Quantity);
}

We use the TypeAdapterConfig generic class with the OrderItem class as the source and the OrderItemShortInfoDto class as our destination. Then, we use the Map() method to map properties from our source object to the corresponding properties of the destination object.

Lastly, we need to call the Scan() method inside the RegisterMapsterConfiguration() method.

TypeAdapterConfig.GlobalSettings.Scan(Assembly.GetExecutingAssembly());

The Scan() method scans the assembly and adds the registration to the TypeAdapterConfig.

Now, we can implement a new method in our MappingFunctions class, which we will later use from our controller.

public static OrderItemShortInfoDto CustomMapOrderItemToShortInfoDto()
{
    var orderItemShortInfoDto = _orderItem.Adapt<OrderItemShortInfoDto>();

    return orderItemShortInfoDto;
}

Here, we use the same functionality as the Adapt() method, but our custom mapping from the MapsterConfig class will define how we map the data.

Let’s add a controller action.

[HttpGet("short-order-item")]
public IActionResult GetShortOrderItem()
{
    var orderItem = MappingFunctions.CustomMapOrderItemToShortInfoDto();

    return Ok(orderItem);
}

Conclusion

In this article, we've explored how to leverage Mapster within ASP.NET Core applications for efficient object mapping. We began by installing the Mapster NuGet package and setting up our environment with entity and DTO classes.

We then delved into basic object mapping using Mapster, covering scenarios such as mapping to new and existing objects, as well as mapping collections. By utilizing Mapster's intuitive syntax and powerful features, we streamlined the process of transforming data between different object types.

Furthermore, we explored custom mapping functionalities offered by Mapster, such as mapping to different members and implementing custom mapping logic. These advanced features empower developers to handle complex mapping scenarios with ease, enhancing the flexibility and maintainability of their applications.

By the end of this article, we've gained a deeper understanding of how Mapster can significantly simplify the mapping process in ASP.NET Core applications, allowing developers to focus more on building robust and scalable solutions rather than getting bogged down in tedious mapping tasks. With its ease of use and powerful capabilities, Mapster proves to be a valuable tool for enhancing productivity and code quality in ASP.NET Core development projects.


Recommended Free Ebook
Similar Articles