Mapperly
Mapperly offers a cleaner alternative to AutoMapper, using attributes to create concise, readable mappings. Mapperly excels in complex scenarios and provides clear compile-time warnings for missing configurations, saving you from debugging headaches.
At some point in your career, you will be manually mapping model A to model B, model C to model D, etc., until you get really, and I mean really, fed up with it. Then, you want to try and make it easier, faster, and better for the next models you will have to map.
Most people will know about AutoMapper, the de facto library for creating dotnet mappers. However, there’s a new kid on the block with some sweet promises. AutoMapper along with others and manual mappings can get messy. It can be hard to pinpoint what properties you forgot to map, or which mappings you're missing.
The new kid is called Mapperly, and it is a library for creating mappers with the help of source generation which makes it:
- faster (uses zero reflection)
- provide a better developer experience (DX)
- not hard to learn, as it’s mainly just attributes
Let’s have a look at how to use Mapperly, first let me sketch an example of two simple models that we want to map, with only some minor differences for now:
Model A:

Model B:

Our mapper to map between both models would look like:

Here the methods are both named Map, but you could be more explicit if you want to be. Isn't this nice and concise? But of course, this is a very straightforward example. Take note of the partial keywords which is because the actual mapping code is being generated for us by Mapperly. This is perfectly readable code by the way, here is a snippet of what Mapperly generates (not the full file):

As you can see, it generated an enum-to-string for the Element and array-to-array method, all perfectly viewable and readable code.
But this is just the beginning.
Next up let’s try a more complicated mapping, showcasing how to map nested models, ignoring "leftover" properties and generating a value for an otherwise empty mapped property:
Model C includes a new ID field and Origin-type property:

Model D ignores the Id field and doesn't use the nested Origin property:

As soon as I added the "Id" property on the Dragon, the mapper code gave this warning in my IDE:
The member Id on the mapping source type DragonMapperly.Dragon is not mapped to any member on the mapping target type DragonMapperly.DragonModel
And the same kind of thing happened for every other mis(sed)-configuration. For this example let's generate a new Guid when mapping from the DragonModel to a Dragon, but ignore (leave out) the Id field when mapping from Dragon to DragonModel. Also, we are flat-mapping the Dragon.Origin to the DragonModel. This is actually the default, but the attribute makes it more clear for this example. We are also unflatting from DragonModel to Dragon.Origin. This is not the default, so we need those two MapProperty attributes.
Adjusting for these changes, our mapper now looks like this:

Easy enough, right? With the Use-notation, we can use any method in the same class. This comes in very handy for generating values, using other Mapperly-mapping methods to map other models, etc.
Like I said, in his process, Mapperly is telling us exactly what properties we are forgetting to map. This has saved me a few times already from needing to debug huge mappers to see what was missing from my configurations in other libraries or manual mappings.
Anyways, I hope you have learned something today, and got curious enough about Mapperly to use it in your next app or project!