Home > Software engineering >  ASP.NET Core - AutoMapper.AutoMapperMappingException: Missing type map configuration or unsupported
ASP.NET Core - AutoMapper.AutoMapperMappingException: Missing type map configuration or unsupported

Time:12-19

In my ASP.NET Core Web API, I have IdentityDbContext:

public class MyDbContext : IdentityDbContext<ApplicationUser, ApplicationRole, long, IdentityUserClaim<long>, ApplicationUserRole, IdentityUserLogin<long>, IdentityRoleClaim<long>, IdentityUserToken<long>>
{
    public MyDbContext(DbContextOptions<MyDbContext> options)
        : base(options)
    {
    }

    public DbSet<ApplicationRole> ApplicationRole { get; set; }
    public DbSet<ApplicationUserRole> ApplicationUserRole { get; set; }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);

        builder.Entity<ApplicationUser>(entity =>
        {
            entity.Property(u => u.Id).ValueGeneratedOnAdd();
            entity.HasIndex(u => u.Email).IsUnique();
            entity.HasIndex(u => u.UserName).IsUnique();
        });
        builder.Entity<ApplicationRole>(entity =>
        {
            entity.Property(r => r.Id).ValueGeneratedOnAdd();
            entity.HasIndex(r => r.Name).IsUnique();
        });
}

IdentityModel:

 public class ApplicationUser : IdentityUser<long>
 {
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string MobileNumber { get; set; }

    [JsonIgnore]
    public bool? IsDeleted { get; set; }
    public DateTime? LastLogin { get; set; }
    public ICollection<ApplicationUserRole> UserRoles { get; set; }
 }

 public class ApplicationRole : IdentityRole<long>
 {
    public ICollection<ApplicationUserRole> UserRoles { get; set; }
 }

 public class ApplicationUserRole : IdentityUserRole<long>
 {
    public override long UserId { get; set; }
    public override long RoleId { get; set; }
    public virtual ApplicationUser User { get; set; }
    public virtual ApplicationRole Role { get; set; }
 }
} 

LoginRequestDto:

public class LoginRequestDto
{
    [Required]
    [JsonProperty(PropertyName = "username")]
    public string UserName { get; set; }

    [Required(ErrorMessage = "The password is required!")]
    public string Password { get; set; }
}

UserDto:

public class UserDto
{
    public long Id { get; set; }
    public string Firstname { get; set; }
    public string Lastname { get; set; }
    public string Email { get; set; }
    public string UserName { get; set; }
    public string MobileNumber { get; set; }
    public DateTime LastLogin { get; set; }
}

AuthMapper:

public class AuthMapperProfile : Profile
{
    public AuthMapperProfile()
    {
        CreateMap<ApplicationUser, UserDto>();

}

Services:

public interface IAuthService
{
    Task<GenericResponseDto<object>> LoginUser(LoginRequestDto request);
}

public class AuthService : IAuthService
{
    private readonly UserManager<ApplicationUser> _userManager;
    private readonly RoleManager<ApplicationRole> _roleManager;
    private readonly IConfiguration _configuration;
    private readonly IMapper _mapper;
    private readonly MyDbContext _context;

    public AuthService(
        UserManager<ApplicationUser> userManager,
        RoleManager<ApplicationRole> roleManager,
        IConfiguration configuration,
        IMapper mapper,
        MyDbContext context

    )
    {
        _userManager = userManager;
        _roleManager = roleManager;
        _configuration = configuration;
        _mapper = mapper;
        _context = context;
    }

    public async Task<GenericResponseDto<object>> LoginUser(LoginRequestDto request)
    {
        var user = await _userManager.FindByNameAsync(request.UserName);
        var response = new GenericResponseDto<object>();

        if (user != null && await _userManager.CheckPasswordAsync(user, request.Password))
        {
            var roles = await _userManager.GetRolesAsync(user);
            var authClaims = new List<Claim>
            {
                new Claim(ClaimTypes.Name, user.UserName),
                new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
            };
            foreach (var userRole in roles)
            {
                authClaims.Add(new Claim(ClaimTypes.Role, userRole));
            }
            var authSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["JWT:Secret"]));
            var token = new JwtSecurityToken(
                issuer: _configuration["JWT:ValidIssuer"],
                audience: _configuration["JWT:ValidAudience"],
                expires: DateTime.Now.AddHours(3),
                claims: authClaims,
                signingCredentials: new SigningCredentials(authSigningKey, SecurityAlgorithms.HmacSha256)
            );

            response.Result = new
            {
                token = new JwtSecurityTokenHandler().WriteToken(token),
                user = _mapper.Map<UserDto>(user),
                expires = token.ValidTo
            };
            response.StatusCode = 200;
            user.LastLogin = DateTime.Now;
            try
            {
                await _context.SaveChangesAsync();
            }
            catch (Exception ex)
            {
                response.Error = new ErrorResponseDto() { ErrorCode = 500, Message = ex.Message };
            }
            return response;
        }

        response.StatusCode = 400;
        response.Error = new ErrorResponseDto { ErrorCode = 400, Message = "Invalid Username or Password!" };

        return response;
    }
}

I got this error:

AutoMapper.AutoMapperMappingException: Missing type map configuration or unsupported mapping.

Mapping types: Object -> UserDto System.Object -> DDM.API.Core.DTOs.v1.Authentication.UserDto at lambda_method198(Closure , Object , UserDto , ResolutionContext ) at DDM.API.Core.Services.v1.Concrete.AuthService.LoginUser(LoginRequestDto request) in C:\Users\MyApp\Core\Services\v1\Concrete\AuthService.cs:line 78

This is line 78:

response.Result = new

startup.cs:

  // Auto mapper
  services.AddAutoMapper(typeof(Startup));

  // Dependency Injection
  services.AddScoped<IAuthService, AuthService>();

controller:

    [Produces("application/json")]
    [HttpPost("login")]
    public async Task<ActionResult<GenericResponseDto<object>>> Login(LoginRequestDto loginRequest)
    {
        var response = await _authService.LoginUser(loginRequest);
        Response.StatusCode = response.StatusCode ?? StatusCodes.Status200OK;
        return new JsonResult(response);
    }

What do I do to resolve this?

Thanks

CodePudding user response:

For some reason, your mapping Profile is not taken into account, the error message supports this, the error message says Automapper uses mapping of Object to UserDto, instead of ApplicationUser to UserDto.

Try configure the mapper in an alternate way

var config = new MapperConfiguration(cfg => {
    cfg.AddMaps(myAssembly);
});

IMapper mapper = config.CreateMapper();

services.AddSingleton(mapper);

Another option, try mapping manually

var config = new MapperConfiguration(cfg => {
    cfg.CreateMap<ApplicationUser, UserDto>();
});
  • Related