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
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
...
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; }
}
}
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>();
}
}
}
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();
}
...
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)
Do you find benefits to automapper for anything other than basic models given the performance issues?
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.
I avoid automapper like the plague.
here's why: softwareengineering.stackexchange....
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.