Goal: To inject IHttpContextAccessor
as a dependency into autmapper profile 's constructor
Why: I need to pass in the current user 's identity 's name as part of construction of one of my domain objects
Issue The obtained User identity is always null
What do I have so far?
Startup.cs
mc.AddProfile(new DtoToOtherProfile(new HttpContextAccessor()));
//OR
var mapperConfiguration = new MapperConfiguration(mc =>
{
IServiceProvider provider = services.BuildServiceProvider();
mc.AddProfile(new DtoToOtherProfile(provider.GetService<IHttpContextAccessor>()));
});
DtoToOtherProfile.cs
public DtoToOtherProfile(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
CreateMap<MyDto, MyOther>()
.ConstructUsing(myDto => new myOther(myDto.prop1, myDto .prop2, _httpContextAccessor.HttpContext.User.Identity.Name)); // the name is what i intend to pass
// other mapping
}
Controller.cs
public async Task<IActionResult> Create([FromBody]MyDto model)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
// save campaign
var myOtherModel = _mapper.Map<MyOther>(model);
// myOtherModel.UserName is always null
// rest
}
Is there something am missing? Pointers please?
I believe the right way to do it is not to inject IHttpContextAccessor
in the Profile
but create a separate IValueResolver
and inject there the IHttpContextAccessor
. So just do the following, where i want to get the user claims for the httpcontext
In your StartUp.cs
inside ConfigureServices
add
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddAutoMapper();
Create a Profile with your mappings
public class MappingProfile : Profile
{
public MappingProfile()
{
CreateMap<QueryUniqueDto, QueryUnique>()
.ForMember(s=>s.UserClaim,opt=>opt.MapFrom<IdentityResolver>());
}
}
Create the IValueResolver
public class IdentityResolver : IValueResolver<QueryUniqueDto, QueryUnique, UserClaim>
{
private IHttpContextAccessor _httpContextAccessor;
public IdentityResolver(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
public UserClaim Resolve(QueryUniqueDto source, QueryUnique destination, UserClaim destMember, ResolutionContext context)
{
return Helper.GetClaimsFromUser(_httpContextAccessor.HttpContext?.User.Identity as ClaimsIdentity);
}
}
That's working amazing!!!
The problem is that AutoMapper configuration is usually singleton. It should be singleton because constructing it is quite heavy. But the username in the request is not singleton-scope. You will most likely have to find a different solution rather than using AutoMapper.
One option I though of:
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
IServiceProvider provider = services.BuildServiceProvider();
var mapperConfiguration = new MapperConfiguration(mc =>
{
mc.AddProfile(new DtoToOtherProfile(provider.GetRequiredService<IHttpContextAccessor>()));
});
This builds the service provider and fetches the context accessor from the container. However, this did not work.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With