Context
Migrate AutoMapper to other frameworks like Mapster might not be straightforward if you have a large number of mapping profiles. This article shows one efficient approach to use GenAI coding tools like Github Copilot to migrate automatically.
Note - This article doesn't talk about Mapster itself, you can learn and find more details about Mapster from its official website: https://github.com/MapsterMapper/Mapster
Create an issue on GitHub with instructions
Let's start creating an issue with instructions to guide the tool to migrate from AutoMapper to Mapster.
The following instruction template was generated using AI tool for one of my projects. Please replace your mapping profiles accordingly. If you don't use GitHub Copilot, you can directly create a prompt markdown file with the following content and then attach it as context for your AI Coding tool.
**_Scope:_**
- backend/Project.Data/Mapping/MappingProfile1.cs
- backend/Project.Data/Mapping/MappingProfile2.cs
**_Extra scope (optional):_**
Please consider whether it makes sense to move the mapping references in controllers into data services so that the business layers don't need to understand how entity are mapped. This helps to switch to other frameworks in future if necessary without touching business layers like controllers, etc.
For example, AccountController uses the current AutoMapper directly:
`var userViewModel = mapper.Map<UserWithRolesViewModel>(user);`
**_Recommended approach:_**
Migrating from **AutoMapper** to **Mapster** is a straightforward process that can enhance your application's performance. The key steps involve replacing the old library with the new one, converting mapping configurations, and updating your code to use Mapster's syntax.
**Migration Steps**
1. **Installation and Removal:** Begin by installing the **Mapster** and **Mapster.DependencyInjection** NuGet packages. Then, remove the **AutoMapper** package to ensure you catch all references that need to be updated.
`dotnet add package Mapster`
`dotnet add package Mapster.DependencyInjection`
`dotnet remove package AutoMapper`
2. **Service Injection:** Configure Mapster for dependency injection by adding `services.AddMapster()` in your `Program.cs` or `Startup.cs` file. This allows you to inject `IMapper` from Mapster, making the transition seamless if you were already using dependency injection with AutoMapper.
3. **Converting Configurations:**
* **Simple Mappings:** Mapster automatically handles simple mappings where property names match, so you can simply remove these AutoMapper configurations.
* **Custom Mappings:** For complex logic, like renaming properties or custom value transformations, translate AutoMapper's `ForMember` syntax into Mapster's `TypeAdapterConfig.NewConfig().Map()` syntax. For instance, creating a `FullName` property from `FirstName` and `LastName` would be done using `.Map(dest => dest.FullName, src => $"{src.FirstName} {src.LastName}")`.
4. **Replacing Mapping Calls:** Replace all calls to `IMapper.Map()` or static `Mapper.Map()` with Mapster's concise `Adapt` extension method. You can use `sourceObject.Adapt<Destination>()` to create a new destination object or `sourceObject.Adapt(destObject)` to map to an existing one.
5. **Handling Specific Scenarios:** Mapster provides specific methods for various needs. Use the `AdaptIgnore` attribute or `Ignore` in `TypeAdapterConfig` to exclude properties from mapping. For immutable types, use the `MapWith` method to create the destination instance explicitly.
**Handling Nulls and Inherited Classes**
**Handling Nulls:**
* By default, Mapster does not overwrite existing properties on a destination object with `null` from the source when using `.Adapt(destObject)`.
* To globally ignore null values during mapping, you can set `TypeAdapterConfig.GlobalSettings.Default.IgnoreNullValues(true)`. Alternatively, you can apply this on a per-configuration basis.
**Mapping Inherited Classes (Polymorphic Mapping):**
* Mapster handles polymorphic mapping through the `.Include()` method, which is the equivalent of AutoMapper's `IncludeBase`.
* You must configure the base mapping and then use `.Include<DerivedSource, DerivedDestination>()` for each derived type.
* Mapster will automatically identify and map the correct derived types at runtime, allowing you to map collections of a base type (e.g., `List<Animal>`) and have each item correctly translated to its corresponding derived DTO (e.g., `DogDto` or `CatDto`).
**Migrating AutoMapper's `ReverseMap()`**
AutoMapper's `ReverseMap()` creates a two-way mapping for a single configuration. In Mapster, the equivalent is the `.TwoWays()` method.
**AutoMapper Example:**
`CreateMap<User, UserDto>().ReverseMap();`
**Mapster Equivalent:**
`TypeAdapterConfig<User, UserDto>.NewConfig().TwoWays();`
The `.TwoWays()` method creates a bi-directional mapping between the source and destination types. This is particularly useful for scenarios where you need to map back and forth between a domain model and a DTO, such as in API controllers where you might map a DTO to a domain object for an update operation and then map the result back to a DTO for the response.
**Summary**
The migration is best handled **iteratively**, converting small batches of mappings at a time to allow for thorough testing. This gradual approach minimizes the risk of errors and ensures a smooth transition to Mapster's high-performance and compile-time-safe mapping capabilities.
Assign the issue to Copilot
Once the issue is created, you can assign the issue to GitHub Copilot agent. The agent will complete the changes in one PR.
After a couple of minutes, the PR is ready for me to review.
Notes
- AI generated code might not be accurate. Make sure you review carefully and also perform sufficient regression testing to ensure existing functionality are still working properly.
- You can tweak the instructions to migrate from Mapster to AutoMapper or a different alternative framework.
Through this approach, we can potentially save much time to migrate from one mapping framework to another. This approach is also widely adopted in my daily engineering activities, which tremendously increases my productivity.