Mapping entities to DTOs with AutoMapper

AutoMapper (http://automapper.org/) is an object-to-object mapper that use conventions and configurations to reduce the amount of code you need to write. To use AutoMapper, you need to install the AutoMapper NuGet package and then configure the mapping you wish to support. After the mappings are configured, you need to create an instance of the mapper and use it to run mappings.

Since such mappings are stateless and exist across your application, I usually define them inside the static constructor of the classes that need them (in our case, the Controller), and then use the mapper throughout application lifetime, but if the mappings are shareable between classes, then you can create a shared class to host those mappings. For example, in the ProductsController object, this is how I configured the mappings and created the mapper: 

private static readonly IMapper _productsMapper;

static ProductsController()
{
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<Product, ProductDTO>()
.ForMember(dto => dto.City, opt => opt.MapFrom(product => product.City))
.ForMember(dto => dto.Category, opt => opt.MapFrom(product => product.Category.ParentCategory.Name))
.ForMember(dto => dto.Subcategory, opt => opt.MapFrom(product => product.Category.Name));

cfg.CreateMap<City, CityDTO>()
.ForMember(dto => dto.Id, opt => opt.MapFrom(city => city.CityId));

// Other mappings
});
_productsMapper = config.CreateMapper();
}

You'll note from the preceding code block that I didn't need to define the mapping between every property to the destination property. AutoMapper has a set of conventions it uses, and, by default, will map properties with the same name.

Now, we can use the mapper we created and stored in the _productsMapper member when the user navigates to a specific product:

[HttpGet("{id}", Name = nameof(GetProduct))]
public async Task<ActionResult<ProductDTO>> GetProduct(int id)
{
var product = await _context.Products
.Include(p => p.Category)
.ThenInclude(c => c.ParentCategory)
.SingleOrDefaultAsync(p => p.ProductId == id);
if (product == null)
{
return NotFound();
}
return Ok(_productsMapper.Map<ProductDTO>(product));
}

AutoMapper can also map a collection of objects to a collection of DTOs automatically. For example, this is how we return the results of the user's product search:

[HttpGet("search/{keyword}")]
public async Task<ActionResult<ProductDTO[]>> SearchProducts(string keyword)
{
List<Product> products = await _context.Products
.Include(p => p.Category)
.ThenInclude(c => c.ParentCategory)
.Where(p => p.Title.Contains(keyword))
.ToListAsync();

return Ok(_productsMapper.Map<ProductDTO[]>(products));
}

There are many more options that AutoMapper allows you to use to save you the burden of writing repeatable mapping code. You can find more details in the official documentation at http://docs.automapper.org/en/stable/.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.119.124.49