It is pretty straightforward but creates a strong bond between the generated class and its consumers. You can use those static methods if having a hard dependency on a static class is acceptable for your project.The last way to map objects we are exploring is very similar, but we create an extension method in the same class instead of just a static method. Here’s the new method:
public static partial NotEnoughStock ToDto(this NotEnoughStockException exception);
The generated code for that method looks like the following (formatted):
public static partial NotEnoughStock ToDto(this NotEnoughStockException exception)
{
var target = new NotEnoughStock(
exception.AmountToRemove,
exception.QuantityInStock,
exception.Message
);
return target;
}
The only difference is the addition of the this keyword, making a regular static method into an extension method that we can use like this:
catch (NotEnoughStockException ex)
{
return Results.Conflict(ex.ToDto());
}
An extension method is more elegant than a static method, yet it creates a bond similar to the static method. Once again, choosing how you want to proceed with your mapping is up to you.One noteworthy thing about Mapperly is that its analyzers yield information, warnings, or errors when the mapping code is incorrect or potentially incorrect. The severity of the messages is configurable. For example, if we add the following method in the ExceptionMapper class, Mapperly yields the RMG013 error:
public static partial Product NotEnoughStockExceptionToProduct(
NotEnoughStockException exception
);
Error message:
RMG013 Core.Models.Product has no accessible constructor with mappable arguments
Moreover, the two exception mapper methods yield messages about properties that do not exist on the target class as information. Here’s an example of such a message:
RMG020 The member TargetSite on the mapping source type Core.ProductNotFoundException is not mapped to any member on the mapping target type ProductNotFound
With those in place, we know when something is or can be wrong, which safeguards us from misconfigurations.Let’s wrap this chapter up.
Summary
Object mapping is an unavoidable reality in many cases. However, as we saw in this chapter, there are several ways of implementing object mapping, taking that responsibility away from the other components of our applications or simply coding it inline manually.At the same time, we took the opportunity to explore the Aggregate Services pattern, which gives us a way to centralize multiple dependencies into one, lowering the number of dependencies needed in other classes. That pattern can help with the too-many-dependencies code smell, which, as a rule of thumb, states that we should investigate objects with more than three dependencies for design flaws. When moving dependencies into an aggregate, ensure there is cohesion within the aggregate to avoid adding unnecessary complexity to your program and just moving the dependencies around.We also explored leveraging the Façade pattern to implement a mapping façade, which led to a more readable and elegant mapper.Afterward, we implemented a mapper service that mimicked the façade. Despite being less elegant in its usage, it was more flexible.We finally explored is AutoMapper and Mapperly, two open-source tools that do object mapping for us, offering us many options to configure the mapping of our objects. As we explored, just using the default convention of AutoMapper allowed us to eliminate all of our mapping code. On Mapperly’s side, we had to define the mapper contracts using partial classes and methods to let its code generator implement the mapping code for us. You can choose from many existing object mapper libraries, AutoMapper being one of the oldest, most famous, and hated at the same time, while Mapperly is one of the newest and fastest but yet in its infancy.Hopefully, as we are putting more and more pieces together, you are starting to see what I had in mind at the beginning of this book when stating this was an architectural journey.Now that we are done with object mapping, we explore the Mediator and CQRS patterns in the next chapter.
Leave a Reply