Can't Figure Out How To Use AutoMapper With Post Action In RESTful Api

Viewed 327

I have a simple RESTful API and this is the post route handler I'm trying to apply AutoMapper in:

    [HttpPost]
    [Route("[action]")]
    public async Task<IActionResult> CreateHotel([FromBody]Hotel hotelCreateDto)
    {
        var hotel = _mapper.Map<Hotel>(hotelCreateDto);

        var createdHotel = await _hotelService.CreateHotel(hotel);

        var hotelReadDto = _mapper.Map<HotelReadDto>(createdHotel);

        return CreatedAtAction("GetHotelById", new { id = hotelReadDto.Id }, hotelReadDto);
    }

So in the request I get a hotelCreateDto which looks like that:

 public class HotelCreateDto
{
    [StringLength(50)]
    [Required]
    public string Name { get; set; }

    [StringLength(50)]
    [Required]
    public string City { get; set; }
}

and I map this to Hotel entity:

public class Hotel
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    [StringLength(50)]
    [Required]
    public string Name { get; set; }

    [StringLength(50)]
    [Required]
    public string City { get; set; }
}

and a new hotel object is created in the next line. However when hotelReadDto is going to be assigned to the new mapped object, a 500 error occurs: "AutoMapper.AutoMapperMappingException: Missing type map configuration or unsupported mapping."

Could you catch a mistake here? I don't know where I'm doing wrong.

Edit: there'S also this things after the error above: "Mapping types: Object -> HotelReadDto System.Object -> HotelFinder.DTO.DTOs.HotelReadDto"

Edit2: Here is the code in the Configure Services:

services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies());

And in the Profile class:

public class HotelProfile : Profile
{
    public HotelProfile()
    {
        CreateMap<Hotel, HotelReadDto>();
        CreateMap<HotelCreateDto, Hotel>();
    }
}
1 Answers

Add this in your services in startup :

it's reusable and cleaner

 public void ConfigureServices(IServiceCollection services)
{
            services.AddAutoMapper(Assembly.GetExecutingAssembly());
}

add these interface and class in your project

public interface IMapFrom<T>
{
        void Mapping(Profile profile) => profile.CreateMap(typeof(T), GetType());
}
using AutoMapper;
using System;
using System.Linq;
using System.Reflection;

    public class MappingProfile : Profile
    {
        public MappingProfile()
        {
            ApplyMappingsFromAssembly(Assembly.GetExecutingAssembly());
        }

        private void ApplyMappingsFromAssembly(Assembly assembly)
        {
                var types = assembly.GetExportedTypes()
                .Where(t => t.GetInterfaces()
                .Any(i =>i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IMapFrom<>)))
                .ToList();

            foreach (var type in types)
            {
                var instance = Activator.CreateInstance(type);

                var methodInfo = type.GetMethod("Mapping")
                    ?? type.GetInterface("IMapFrom`1").GetMethod("Mapping");

                methodInfo?.Invoke(instance, new object[] { this });

            }
        }
    }

and your dto be like this (map hotel to HotelDto):

 public class HotelCreateDto : IMapFrom<HotelCreateDto>
    {
        [StringLength(50)]
        [Required]
        public string Name { get; set; }

        [StringLength(50)]
        [Required]
        public string City { get; set; }
        public void Mapping(Profile profile)
        {
            profile.CreateMap<Hotel,HotelCreateDto>();
        }
    }
Related