I am using AutoMapper 6.2.2 with .NET Core 2.0 and its default dependency injection mechanism to map between models and DTOs.
I need DI in my AutoMapper configs because I have to perform an AfterMap<Action>
that needs some injected components.
The thing is, for some models that have constructors which parameters match some source member, when I enable DI for AutoMapper (add services.AddAutoMapper()
), these constructors are by default called and fed with data, that then breaks my operations with EF.
public class UserDTO
{
public string Name { get; set; }
public string Email { get; set; }
public ICollection<RoleDTO> Roles { get; set; }
}
public class User
{
public string Name { get; set; }
public string Email { get; set; }
public ICollection<RoleInUser> RoleInUsers { get; } = new List<RoleInUser>();
public ICollection<Role> Roles { get; }
public User()
{
Roles = new JoinCollectionFacade<Role, User, RoleInUser>(this, RoleInUsers);
}
public User(string name, string email, ICollection<Role> roles) : this()
{
Roles.AddRange(roles);
}
}
public class UserProfile : Profile
{
public UserProfile()
{
CreateMap<UserDTO, User>()
.ForMember(entity => entity.Roles, opt => opt.Ignore())
.AfterMap<SomeAction>();
}
}
In the previous snippet, User(name, email, roles)
gets called with the list of roles.
My mapper configuration is the following (note the DisableConstructorMapping()
option)
protected override MapperConfiguration CreateConfiguration()
{
var config = new MapperConfiguration(cfg =>
{
cfg.DisableConstructorMapping();
// Add all profiles in current assembly
cfg.AddProfiles(Assemblies);
});
return config;
}
And my Startup
where everything is set up:
var mapperProvider = new MapperProvider();
services.AddSingleton<IMapper>(mapperProvider.GetMapper());
services.AddAutoMapper(mapperProvider.Assemblies);
Modifying the profile to configure which ctor to use with ConstructUsing
public UserProfile()
{
CreateMap<UserDTO, User>()
.ForMember(entity => entity.Roles, opt => opt.Ignore())
.ConstructUsing(src => new User())
.AfterMap<SomeAction>();
}
It works as expected, but this forces me to include this boilerplate statement in every Map configuration, and the model is quite big.
Without dependency injection (this need arosed recently), it worked smoothly with the first snippet (no need for ConstructUsing
).
I've searched for this scenario but haven't found anything. Is adding ConstructUsing
to every Map the way to go? Is there any better option? Or maybe I'm doing something
completely wrong...