1
votes

I have an NET Core application and I need to get the current user token for map an object with Automapper.

This is my NET Core controller:

public async Task<IActionResult> Add([FromBody] EnrollSkill request)
{
    var model = _autoMapper.Map<Domain.Entities.UserSkill>(request);

    var response = await _userService.AddSkillAsync(model);

    return Ok();
}

Note that I'm trying to map EnrollSkill viewmodel to UserSkill domain model.

This is my EnrollSkill class:

public class EnrollSkill
{
    public string Id { get; set; } // Skill Id (not user Id)
    public int KnowledgeLevel { get; set; }
    public int Order { get; set; }
}

And this is my UserSkill class:

public class UserSkill : Base
{
    public int KnowledgeLevel { get; set; }
    public int Order { get; set; }
    public DateTime CreatedDate { get; set; }

    public string UserId { get; set; }
    public User User { get; set; }

    public string SkillId { get; set; }
    public Skill Skill { get; set; }
}

In my repository service, I need populate UserId to invoke SaveChangesAsync()

This UserId exists in the Controller because I can read the user claims with:

User.Claims

Now, I have this profile in Automapper:

CreateMap<EnrollSkill, UserSkill>().
    BeforeMap((from, to) =>
    {
        to.UserId = "12345"
    });

But, how can I read correctly this value in Automapper? What's the best way?

I'm trying to populate this UserId in controller with a method named SetUserId, but I think it's a wrong solution because I'm messing my domain entity:

var model = _autoMapper.Map<Domain.Entities.UserSkill>(request).SetUserId(CurrentUserId);

Thanks

1
I've got an approximation to solution injecting IHttpContextAccessor in Automapper Profile, but I think that is not elegant.. any suggestions? - Sergio
@LucianBargaoanu thanks! but this solution forces me a pass value in every map - Sergio
I post this link because the answer is here: stackoverflow.com/questions/49822221/… - Sergio

1 Answers

4
votes

I think that the best solution is inject IHttpContextAccessor

In my Startup class I added Automapper service throught extension method and I passed IHttpContextAccessor:

services.AddAutomapperConfiguration(_serviceProvider.GetService<IHttpContextAccessor>());

Now, in my extension method, I passed IHttpContextAccessor to my Automapper Profile:

public static void AddAutomapperConfiguration(this IServiceCollection services, 
    IHttpContextAccessor httpContextAccessor)
{
    var automapperConfig = new MapperConfiguration(configuration =>
    {            
        configuration.AddProfile(new Profiles(httpContextAccessor));
    });

    var autoMapper = automapperConfig.CreateMapper();

    services.AddSingleton(autoMapper);
}

And finally, in my Profile I get the user Id through helper that reads user claims from IHttpContextAccessor

public class Profiles : Profile
{
    private readonly IHttpContextAccessor _httpContextAccessor;

    public Profiles(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor;

        CreateMap<Models.User.EnrollSkill, UserSkill>()
            .AfterMap((src, dest) =>
            {
                dest.UserId = IdentityHelper.GetClaimValue(_httpContextAccessor, IdentityHelper.Claims.Id);
            });

    }
}

I do not know if it is the best solution, but it works correctly