How to read User Claims from Automapper Value Resolver

Automatic mapping properties from User Claims

Sometimes we need to send to our services DTOs that include existing data in the user’s claims.

To avoid fattening controllers, let’s see how to make Automapper do this work for us.

In our example, we will try to create a company and only receive the name and description, but obviously, we are interested in knowing which user has made this action.

The model that exposes the API is CreateCompany and the DTO that we send to the service is CreateCompanyDto. Both models are the same, except the last one, which incorporates a property that stores the user’s identifier.

Step 1: Install Nuget packages

To make this solution to work correctly, we will need these two packages:

Step 2: Register IHttpContextAccessor interface into DI container

Why? because IHttpContextAccessor is not registered by default for performance reasons. You can read on Github a thread with a discussion about it.

public void ConfigureServices(IServiceCollection services)
{
    services.AddTransient<IHttpContextAccessor, HttpContextAccessor>();
    
    services.AddAutoMapper(configuration =>
    {
        configuration.AddProfile<CompanyProfile>();
    });

    services.AddMvc();
}

Step 3: Create Automapper profile

On our Automapper profile, we will specify which “custom value solver” we will use to recover the desired value of the user’s claims

public class CompanyProfile : Profile
{
    public CompanyProfile()
    {
        CreateMap<CreateCompany, CreateCompanyDto>()
            .ForMember(destination => destination.UserId, option => option.ResolveUsing<UserIdResolver>());
    }
}

Step 4: Create “Custom Value Resolver”

We must inject IHttpContextAccessor interface on class constructor so that afterwards, the “Resolve” method is able to read the property.

In this case, we read “NameIdentifier” claim as our user identifier, but we can read anything.

public class UserIdResolver : IValueResolver<object, object, string>
{
    private readonly IHttpContextAccessor _contextAccessor;

    public UserIdResolver(IHttpContextAccessor contextAccessor)
    {
        _contextAccessor = contextAccessor;
    }

    public string Resolve(object source, object destination, string destinationMember, ResolutionContext context)
    {            
        return _contextAccessor.HttpContext.User.Claims
            .Where(x => x.Type == ClaimTypes.NameIdentifier)
            .Select(c => c.Value).SingleOrDefault();
    }
}

Step 5: Create controller and mapping data

Now, we will be able to map both classes in a single line and this is because Automapper will be in charge of recovering the value that we need from the claims.

[HttpPost]
[Authorize]
public async Task<IActionResult> CreateCompanyAsync(CreateCompany request)
{
    var mapped = _automapper.Map<CreateCompanyDto>(request);
    
    return Ok(await _companyService.CreateCompanyAsync(mapped));
}