DEV Community

Brandon Weaver
Brandon Weaver

Posted on

AutoMapper

In this part of the series, we'll take advantage of the AutoMapper package and create DTOs (data transfer objects) to manage the content which our endpoints expose.

We'll start by adding the package we need.

dotnet add package AutoMapper.Extensions.Microsoft.DependencyInjection
Enter fullscreen mode Exit fullscreen mode

Next, we'll add the service to our application. At the top of the ConfigureServices method within 'Startup.cs', add the single line of code.

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<Data.AppContext>(opt => opt.UseSqlite(Configuration.GetConnectionString("AppConnection")));

    services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies()); // Add this

    ...
Enter fullscreen mode Exit fullscreen mode

Now we'll add a new folder named 'Dtos' to the primary directory of our application, and we'll add a new file to that folder named 'UserReadDto.cs'.

namespace AspNetCoreWebApiIntro.Dtos
{
    public class UserReadDto
    {
        public string FirstName { get; set; }

        public string LastName { get; set; }
    }
}
Enter fullscreen mode Exit fullscreen mode

We'll add yet another folder to the primary directory named 'Profiles' and add a new file named 'UsersProfile.cs'.

using AutoMapper;

using AspNetCoreWebApiIntro.Dtos;
using AspNetCoreWebApiIntro.Models;

namespace AspNetCoreWebApiIntro.Profiles
{
    public class UsersProfile : Profile
    {
        public UsersProfile()
        {
            CreateMap<User, UserReadDto>();
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Now, we simply need to revisit our users controller and ensure that our read actions return our DTOs which will be mapped from each user via AutoMapper.

using AutoMapper; // New
using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc;

using AspNetCoreWebApiIntro.Data;
using AspNetCoreWebApiIntro.Dtos; // New
using AspNetCoreWebApiIntro.Models;

namespace AspNetCoreWebApiIntro.Controllers
{
    [ApiController]
    [Route("api/[controller]")]
    public class UsersController : ControllerBase
    {
        private readonly AppRepo _repo;
        private readonly IMapper _mapper; // New

        public UsersController(AppRepo repo, IMapper mapper) // Change
        {
            this._repo = repo;
            this._mapper = mapper; // New
        }

        [HttpGet]
        public ActionResult<IEnumerable<UserReadDto>> Index() // Change
        {
            IEnumerable<User> users = this._repo.GetAllUsers(); // New
            return Ok(this._mapper.Map<IEnumerable<UserReadDto>>(users)); // Change
        }

        [HttpGet("{id}", Name = "Show")]
        public ActionResult<UserReadDto> Show(int id) // Change
        {
            User user = this._repo.GetUserById(id);

            if (user != null)
                return Ok(this._mapper.Map<UserReadDto>(user)); // Change
            return NotFound();
        }

        ...
Enter fullscreen mode Exit fullscreen mode

Each endpoint will now return only the first and last name of each user as we have excluded that property from the read DTO.

In the next part of this series, we'll add PATCH and DELETE actions.

Top comments (4)

Collapse
 
flipch profile image
Felipe

Do you find benefits to automapper for anything other than basic models given the performance issues?

Collapse
 
brandonmweaver profile image
Brandon Weaver

To be fair, I don't think that AutoMapper is necessary; you can always map your DTOs yourself. I would say that if it weren't for the sake of simplicity, I would opt out of using it.

Collapse
 
djnitehawk profile image
Dĵ ΝιΓΞΗΛψΚ

I avoid automapper like the plague.
here's why: softwareengineering.stackexchange....

Collapse
 
brandonmweaver profile image
Brandon Weaver

Thanks for the read. I understand that it has many issues. As far as getting others acquainted with the framework, I figured that it is reasonable to use AutoMapper.