Date: 2024-11-02

In this discussion, I will cover five types of AutoMapper that are regularly used in our code. First, I will write all of them in a single controller (though it is considered bad practice to keep all code in a controller action).

Must add builder.Services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies()); line into program.cs and install package <PackageReference Include="AutoMapper" Version="13.0.1" />

Controller:

public class HomeController : Controller
{
    private readonly IMapper _mapper;
    private readonly ILogger<HomeController> _logger;
 
    public HomeController(IMapper mapper, ILogger<HomeController> logger)
    {
        _logger = logger;
        _mapper = mapper;
    }
 
    ## Type 1: Simple Automapper
    // All properties in the DTO are equal to all properties in the Model.
    public IActionResult Index()
    {
        var employeeModelValue = new EmployeeModel
        {
            Code = "A123",
            Name = "Mr X",
            Gender = "Male",
            JoinningDate = DateTime.Parse("2024-01-01")
        };
 
        var employeeDTOValue = new EmployeeDTO
        {
            Code = "B123",
            Name = "Mrs Y",
            Gender = "Female",
            JoinningDate = DateTime.Parse("2024-12-25")
        };
 
        // 1. Mapping EmployeeModel to EmployeeDTO
        var employeeDTO = _mapper.Map<EmployeeDTO>(employeeModelValue);
 
        // 2. Mapping EmployeeDTO to EmployeeModel
        var employeeModel = _mapper.Map<EmployeeModel>(employeeDTOValue);
 
        var employeeViewModel = new EmployeeViewModel
        {
            EmployeeDTO = employeeDTO,
            EmployeeModel = employeeModel
        };
 
        return View(employeeViewModel);
    }
 
    ## Type 2: Semi Advanced Automapper
    // One or two properties of the DTO are not equal to one or two properties of the Model.
    public IActionResult Index2()
    {
        var personValue = new PersonModel
        {
            FirstName = "John",
            LastName = "Doe",
            Age = 30
        };
 
        var personDTOValue = new PersonDTO
        {
            FullName = "John Doe",
            Age = 30
        };
 
        // 1. Mapping PersonModel to PersonDTO
        var personDTO = _mapper.Map<PersonDTO>(personValue);
 
        // 2. Mapping PersonDTO to PersonModel
        var personModel = _mapper.Map<PersonModel>(personDTOValue);
 
        var personViewModel = new PersonViewModel
        {
            PersonDTO = personDTO,
            PersonModel = personModel
        };
 
        return View(personViewModel);
    }
 
    ## Type 3: Advanced Automapper
    // One or two properties of the DTO are not equal to one or two properties of the Model. 
    // Additionally, properties can be modified or added from outside.
    public IActionResult Index3()
    {
        var employeeModelValue = new EmployeeModel
        {
            Code = "A123",
            Name = "Mr X",
            Gender = "Male",
            JoinningDate = DateTime.Parse("2024-01-01")
        };
 
        var employeeDTOValue = new EmployeeDTO
        {
            Code = "B123",
            Name = "Mrs Y",
            Gender = "Female",
            JoinningDate = DateTime.Parse("2024-12-25")
        };
 
        employeeDTOValue.Code = "C123";
        employeeDTOValue.Name = "Mrs Z";
        employeeDTOValue.Gender = employeeModelValue.Gender;
 
        // 1. Mapping EmployeeModel to EmployeeDTO
        var employeeDTO = _mapper.Map<EmployeeDTO>(employeeModelValue);
 
        // 2. Mapping EmployeeDTO to EmployeeModel
        var employeeModel = _mapper.Map<EmployeeModel>(employeeDTOValue);
 
        var employeeViewModel = new EmployeeViewModel
        {
            EmployeeDTO = employeeDTO,
            EmployeeModel = employeeModel
        };
 
        return View(employeeViewModel);
    }
 
    ## Type 4: List of Model Automap
    // Mapping a list of EmployeeModel to a list of EmployeeDTO.
    public IActionResult Index4()
    {
        var employeeModelValueList = new List<EmployeeModel>
        {
            new EmployeeModel
            {
                Code = "D123",
                Name = "Mr X",
                Gender = "Male",
                JoinningDate = DateTime.Parse("2024-01-01")
            },
            new EmployeeModel
            {
                Code = "E123",
                Name = "Mr X",
                Gender = "Male",
                JoinningDate = DateTime.Parse("2024-01-01")
            },
            new EmployeeModel
            {
                Code = "F123",
                Name = "Mr X",
                Gender = "Male",
                JoinningDate = DateTime.Parse("2024-01-01")
            },
            new EmployeeModel
            {
                Code = "G123",
                Name = "Mr X",
                Gender = "Male",
                JoinningDate = DateTime.Parse("2024-01-01")
            }
        };
 
        employeeModelValueList[0].Name = "Mr D";
        employeeModelValueList[1].Name = "Mr E";
        employeeModelValueList[2].Name = "Mr F";
        employeeModelValueList[3].Name = "Mr G";
 
        var employeeDTOValue = new EmployeeDTO
        {
            Code = "H123",
            Name = "Mrs Y",
            Gender = "Female",
            JoinningDate = DateTime.Parse("2024-12-25")
        };
 
        // 1. Mapping a list of EmployeeModel to a list of EmployeeDTO
        var employeeDTO = _mapper.Map<List<EmployeeDTO>>(employeeModelValueList);
 
        // 2. Mapping EmployeeDTO to EmployeeModel
        var employeeModel = _mapper.Map<EmployeeModel>(employeeDTOValue);
 
        var employeeViewModel = new EmployeeViewModelList
        {
            EmployeeDTO = employeeDTO,
            EmployeeModel = employeeModel
        };
 
        return View(employeeViewModel);
    }
 
    ## Type 5: Model and View are not identical
    // Some properties are missing in the model, and some properties are missing in the DTO.
    public IActionResult Index5()
    {
        var bookValue = new BookModel
        {
            Title = "1984",
            Author = "George Orwell",
            YearPublished = 1949,
            Genre = "Dystopian",
            Edition = "First"
        };
 
        var bookDTOValue = new BookDTO
        {
            Title = "1984",
            Author = "George Orwell",
            YearPublished = 1949,
            Genre = "Dystopian",
            Price = 212.12
        };
 
        // 1. Mapping BookModel to BookDTO
        var bookDTO = _mapper.Map<BookDTO>(bookValue);
 
        // 2. Mapping BookDTO to BookModel
        var bookModel = _mapper.Map<BookModel>(bookDTOValue);
 
        var bookViewModel = new BookViewModel
        {
            BookDTO = bookDTO,
            BookModel = bookModel
        };
 
        return View(bookViewModel);
    }
}

DTO:

public class BookDTO
{
    public string Title { get; set; }
    public string Author { get; set; }
    public int YearPublished { get; set; }
    public string Genre { get; set; }
 
 
    // Extra
    public double? Price { get; set; }
    public int? Quantity { get; set; }
    public string Description { get; set; }
}
 
public class EmployeeDTO
{
    public string Code { get; set; }
    public string Name { get; set; }
    public string Gender { get; set; }
    public DateTime? JoinningDate { get; set; }
}
 
public class PersonDTO
{
    public string FullName { get; set; }
    public int Age { get; set; }
 
    //public string FirstName { get; set; }
    //public string LastName { get; set; }
    //public int? Age { get; set; }
}

Model:

public class BookModel
{
    public string Title { get; set; }
    public string Author { get; set; }
    public int YearPublished { get; set; }
    public string Genre { get; set; }
 
    // Extra
    public string Edition { get; set; }
}
 
public class EmployeeModel
{
    public string Code { get; set; }
    public string Name { get; set; }
    public string Gender { get; set; }
    public DateTime? JoinningDate { get; set; }
}
 
public class PersonModel
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int? Age { get; set; }
}

Profiles:

public BookProfile()
{
// Ignore is necessary while property name is same but datatype different (It have other reason also)
    CreateMap<BookModel, BookDTO>()
    .ForMember(dest => dest.Price, opt => opt.Ignore())
    .ForMember(dest => dest.Quantity, opt => opt.Ignore())
    .ForMember(dest => dest.Description, opt => opt.Ignore());
 
    CreateMap<BookDTO, BookModel>();
}
 
public EmployeeProfile()
{
    //CreateMap<EmployeeModel, EmployeeDTO>();
    //CreateMap<EmployeeDTO, EmployeeModel>();
 
    CreateMap<EmployeeModel, EmployeeDTO>().ReverseMap();
}
 
public PersonProfile()
{
    // 1. Map from Person to PersonDTO (Source: PersonModel,  Destination: PersonDTO)
    CreateMap<PersonModel, PersonDTO>()
        .ForMember(dest => dest.FullName, opt => opt.MapFrom(src => $"{src.FirstName} {src.LastName}"))
        .ForMember(dest => dest.Age, opt => opt.MapFrom(src => src.Age ?? 0));
 
    // 2. Map from PersonDTO to Person (Source: PersonDTO,  Destination: PersonModel)
    CreateMap<PersonDTO, PersonModel>()
        .ForMember(dest => dest.FirstName, opt => opt.MapFrom(src => src.FullName.Split()[0]))
        .ForMember(dest => dest.LastName, opt => opt.MapFrom(src => src.FullName.Split().Length > 1 ? src.FullName.Split()[1] : ""))
        .ForMember(dest => dest.Age, opt => opt.MapFrom(src => src.Age));
}

To view the razor page and the shared model (where I store data to send it to the view), visit my GitHub repository: https://github.com/msashoyeb/Project-Collection.