4.2.1 Bug - CreateMap(profileName) never initializes the NamedProfile instance.
See original GitHub issueI’m trying to confirm this is the issue I’m running into as I’m attempting to migrate from v3.3.1 to 4.2.1.
In doing so I came across what seems to be a decent size bug that breaks inheritance and ReverseMap. Possibly more but I’m unfamiliar with this code base.
Calling mapperConfiguration.CreateMap<>()
may instantiate a new NamedProfile instance but never initialize it. See below:
private Profile GetProfile(string profileName)
{
return this._profiles.GetOrAdd(profileName, (Func<string, Profile>) (name => (Profile) new MapperConfiguration.NamedProfile(profileName)));
}
private class NamedProfile : Profile
{
public NamedProfile(string profileName)
: base(profileName)
{
}
protected override void Configure()
{
}
}
The profile instance never gets it’s Initialize()
method called from CreateMap()
and thus never has the private IConfiguration _configurator;
private member set. From what I’ve found, this causes issues with ReverseMap()
and IncludeBase<,>()
functions. Possibly more if anything depends on the Profile
instance using the _configurator
field.
The code below caused me to get a NullReferenceException.
mapperConfiguration.CreateMap<File, FileDto>()
.ForMember(dto => dto.CreatedByUserId, c => c.MapFrom(f => f.CreatedByUserId))
.ForMember(dto => dto.CreatedOn, c => c.MapFrom(f => f.CreatedOn))
.ForMember(dto => dto.Extension, c => c.MapFrom(f => f.Extension))
.ForMember(dto => dto.Id, c => c.MapFrom(f => f.Id))
.ForMember(dto => dto.Md5Hash, c => c.MapFrom(f => f.Md5Hash))
.ForMember(dto => dto.Size, c => c.MapFrom(f => f.Size));
mapperConfiguration.CreateMap<DocumentRevisionFile, FileDto>()
.IncludeBase<File, FileDto>(); // <<<< BREAKS!
System.NullReferenceException: Object reference not set to an instance of an object. at AutoMapper.Profile.CreateMap(Type sourceType, Type destinationType) at AutoMapper.Internal.MappingExpression
2.IncludeBase(Type sourceBase, Type destinationBase) at AutoMapper.Internal.MappingExpression
2.IncludeBaseTSourceBase,TDestinationBase
It doesn’t matter how you register your mappings. I’ve tried both: Mapper.Initialize()
& using new MapperConfiguration(c => { });
Temporary fix:
Since I was moving from v3 to v4, CreateMap<,>()
now takes a string parameter for profileName. For now I just created an extension method to fill this gap until I can confirm we may move to 4.2.1 without other breaking changes.
public static class AutoMapperExtensions
{
public static IMappingExpression<TSource, TTarget> CreateMap<TSource, TTarget>(this IConfiguration configuration)
{
var profile = configuration.CreateProfile(string.Format("{0}|{1}", typeof (TSource).FullName, typeof (TTarget).FullName));
return profile.CreateMap<TSource, TTarget>();
}
}
The CreateProfile
method correctly initializes the profile. Then just return the profile.CreateMap<,>()
;
Issue Analytics
- State:
- Created 7 years ago
- Comments:10 (4 by maintainers)
Top GitHub Comments
@Cephei I took that named profile stuff away because it was really hard to get the order of things right during config time. In 5.0 I gather all config, then apply it, but applying profile names willy-nilly really made my life difficult.
Version 5.0 will most likely be the next release of Automapper. An update to 4.2.1 is probably not going to happen.